dsdb: Do not permit nested event loops when in a transaction, use a nested event...
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blobf064467bf234da862b140dca7e1c51815e985afd
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_wbint.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "idmap.h"
31 #include "../libcli/security/security.h"
33 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
35 *r->out.out_data = r->in.in_data;
38 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
39 NTSTATUS status)
41 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
42 invalidate_cm_connection(&domain->conn);
43 /* We invalidated the connection. */
44 return true;
46 return false;
49 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
51 struct winbindd_domain *domain = wb_child_domain();
52 char *dom_name;
53 char *name;
54 enum lsa_SidType type;
55 NTSTATUS status;
57 if (domain == NULL) {
58 return NT_STATUS_REQUEST_NOT_ACCEPTED;
61 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
62 &dom_name, &name, &type);
63 reset_cm_connection_on_error(domain, status);
64 if (!NT_STATUS_IS_OK(status)) {
65 return status;
68 *r->out.domain = dom_name;
69 *r->out.name = name;
70 *r->out.type = type;
71 return NT_STATUS_OK;
74 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
76 struct winbindd_domain *domain = wb_child_domain();
77 struct lsa_RefDomainList *domains = r->out.domains;
78 NTSTATUS status;
80 if (domain == NULL) {
81 return NT_STATUS_REQUEST_NOT_ACCEPTED;
85 * This breaks the winbindd_domain->methods abstraction: This
86 * is only called for remote domains, and both winbindd_msrpc
87 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
88 * done at the wbint RPC layer.
90 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
91 &domains, &r->out.names);
93 if (domains != NULL) {
94 r->out.domains = domains;
97 reset_cm_connection_on_error(domain, status);
98 return status;
101 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
103 struct winbindd_domain *domain = wb_child_domain();
104 NTSTATUS status;
106 if (domain == NULL) {
107 return NT_STATUS_REQUEST_NOT_ACCEPTED;
110 status = domain->methods->name_to_sid(
111 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
112 r->out.sid, r->out.type);
113 reset_cm_connection_on_error(domain, status);
114 return status;
117 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
118 struct wbint_Sids2UnixIDs *r)
120 uint32_t i, j;
121 struct id_map *ids = NULL;
122 struct id_map **id_ptrs = NULL;
123 struct dom_sid *sids = NULL;
124 uint32_t *id_idx = NULL;
125 NTSTATUS status = NT_STATUS_NO_MEMORY;
127 for (i=0; i<r->in.domains->count; i++) {
128 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
129 struct idmap_domain *dom;
130 uint32_t num_ids;
132 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
133 if (dom == NULL) {
134 DEBUG(10, ("idmap domain %s:%s not found\n",
135 d->name.string, sid_string_dbg(d->sid)));
136 continue;
139 num_ids = 0;
141 for (j=0; j<r->in.ids->num_ids; j++) {
142 if (r->in.ids->ids[j].domain_index == i) {
143 num_ids += 1;
147 ids = talloc_realloc(talloc_tos(), ids,
148 struct id_map, num_ids);
149 if (ids == NULL) {
150 goto nomem;
152 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
153 struct id_map *, num_ids+1);
154 if (id_ptrs == NULL) {
155 goto nomem;
157 id_idx = talloc_realloc(talloc_tos(), id_idx,
158 uint32_t, num_ids);
159 if (id_idx == NULL) {
160 goto nomem;
162 sids = talloc_realloc(talloc_tos(), sids,
163 struct dom_sid, num_ids);
164 if (sids == NULL) {
165 goto nomem;
168 num_ids = 0;
171 * Convert the input data into a list of
172 * id_map structs suitable for handing in
173 * to the idmap sids_to_unixids method.
175 for (j=0; j<r->in.ids->num_ids; j++) {
176 struct wbint_TransID *id = &r->in.ids->ids[j];
178 if (id->domain_index != i) {
179 continue;
181 id_idx[num_ids] = j;
182 id_ptrs[num_ids] = &ids[num_ids];
184 ids[num_ids].sid = &sids[num_ids];
185 sid_compose(ids[num_ids].sid, d->sid, id->rid);
186 ids[num_ids].xid.type = id->type;
187 ids[num_ids].status = ID_UNKNOWN;
188 num_ids += 1;
190 id_ptrs[num_ids] = NULL;
192 status = dom->methods->sids_to_unixids(dom, id_ptrs);
193 DEBUG(10, ("sids_to_unixids returned %s\n",
194 nt_errstr(status)));
197 * Extract the results for handing them back to the caller.
199 for (j=0; j<num_ids; j++) {
200 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
202 if (ids[j].status != ID_MAPPED) {
203 id->xid.id = UINT32_MAX;
204 id->xid.type = ID_TYPE_NOT_SPECIFIED;
205 continue;
208 id->xid = ids[j].xid;
211 status = NT_STATUS_OK;
212 nomem:
213 TALLOC_FREE(ids);
214 TALLOC_FREE(id_ptrs);
215 TALLOC_FREE(id_idx);
216 TALLOC_FREE(sids);
217 return status;
220 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
222 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
223 r->out.sid, r->in.uid);
226 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
228 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
229 r->out.sid, r->in.gid);
232 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
234 struct unixid xid;
235 NTSTATUS status;
237 status = idmap_allocate_uid(&xid);
238 if (!NT_STATUS_IS_OK(status)) {
239 return status;
241 *r->out.uid = xid.id;
242 return NT_STATUS_OK;
245 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
247 struct unixid xid;
248 NTSTATUS status;
250 status = idmap_allocate_gid(&xid);
251 if (!NT_STATUS_IS_OK(status)) {
252 return status;
254 *r->out.gid = xid.id;
255 return NT_STATUS_OK;
258 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
260 struct winbindd_domain *domain = wb_child_domain();
261 NTSTATUS status;
263 if (domain == NULL) {
264 return NT_STATUS_REQUEST_NOT_ACCEPTED;
267 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
268 r->out.info);
269 reset_cm_connection_on_error(domain, status);
270 return status;
273 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
274 struct wbint_LookupUserAliases *r)
276 struct winbindd_domain *domain = wb_child_domain();
277 NTSTATUS status;
279 if (domain == NULL) {
280 return NT_STATUS_REQUEST_NOT_ACCEPTED;
283 status = domain->methods->lookup_useraliases(
284 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
285 &r->out.rids->num_rids, &r->out.rids->rids);
286 reset_cm_connection_on_error(domain, status);
287 return status;
290 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
291 struct wbint_LookupUserGroups *r)
293 struct winbindd_domain *domain = wb_child_domain();
294 NTSTATUS status;
296 if (domain == NULL) {
297 return NT_STATUS_REQUEST_NOT_ACCEPTED;
300 status = domain->methods->lookup_usergroups(
301 domain, p->mem_ctx, r->in.sid,
302 &r->out.sids->num_sids, &r->out.sids->sids);
303 reset_cm_connection_on_error(domain, status);
304 return status;
307 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
308 struct wbint_QuerySequenceNumber *r)
310 struct winbindd_domain *domain = wb_child_domain();
311 NTSTATUS status;
313 if (domain == NULL) {
314 return NT_STATUS_REQUEST_NOT_ACCEPTED;
317 status = domain->methods->sequence_number(domain, r->out.sequence);
318 reset_cm_connection_on_error(domain, status);
319 return status;
322 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
323 struct wbint_LookupGroupMembers *r)
325 struct winbindd_domain *domain = wb_child_domain();
326 uint32_t i, num_names;
327 struct dom_sid *sid_mem;
328 char **names;
329 uint32_t *name_types;
330 NTSTATUS status;
332 if (domain == NULL) {
333 return NT_STATUS_REQUEST_NOT_ACCEPTED;
336 status = domain->methods->lookup_groupmem(
337 domain, p->mem_ctx, r->in.sid, r->in.type,
338 &num_names, &sid_mem, &names, &name_types);
339 reset_cm_connection_on_error(domain, status);
340 if (!NT_STATUS_IS_OK(status)) {
341 return status;
344 r->out.members->num_principals = num_names;
345 r->out.members->principals = talloc_array(
346 r->out.members, struct wbint_Principal, num_names);
347 if (r->out.members->principals == NULL) {
348 return NT_STATUS_NO_MEMORY;
351 for (i=0; i<num_names; i++) {
352 struct wbint_Principal *m = &r->out.members->principals[i];
353 sid_copy(&m->sid, &sid_mem[i]);
354 m->name = talloc_move(r->out.members->principals, &names[i]);
355 m->type = (enum lsa_SidType)name_types[i];
358 return NT_STATUS_OK;
361 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
362 struct wbint_QueryUserList *r)
364 struct winbindd_domain *domain = wb_child_domain();
365 NTSTATUS status;
367 if (domain == NULL) {
368 return NT_STATUS_REQUEST_NOT_ACCEPTED;
371 status = domain->methods->query_user_list(
372 domain, p->mem_ctx, &r->out.users->num_userinfos,
373 &r->out.users->userinfos);
374 reset_cm_connection_on_error(domain, status);
375 return status;
378 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
379 struct wbint_QueryGroupList *r)
381 struct winbindd_domain *domain = wb_child_domain();
382 uint32_t i, num_groups;
383 struct wb_acct_info *groups;
384 struct wbint_Principal *result;
385 NTSTATUS status;
387 if (domain == NULL) {
388 return NT_STATUS_REQUEST_NOT_ACCEPTED;
391 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
392 &num_groups, &groups);
393 reset_cm_connection_on_error(domain, status);
394 if (!NT_STATUS_IS_OK(status)) {
395 return status;
398 result = talloc_array(r->out.groups, struct wbint_Principal,
399 num_groups);
400 if (result == NULL) {
401 return NT_STATUS_NO_MEMORY;
404 for (i=0; i<num_groups; i++) {
405 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
406 result[i].type = SID_NAME_DOM_GRP;
407 result[i].name = talloc_strdup(result, groups[i].acct_name);
408 if (result[i].name == NULL) {
409 TALLOC_FREE(result);
410 TALLOC_FREE(groups);
411 return NT_STATUS_NO_MEMORY;
415 r->out.groups->num_principals = num_groups;
416 r->out.groups->principals = result;
418 TALLOC_FREE(groups);
419 return NT_STATUS_OK;
422 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
424 struct winbindd_domain *domain = wb_child_domain();
425 struct rpc_pipe_client *netlogon_pipe;
426 struct netr_DsRGetDCNameInfo *dc_info;
427 NTSTATUS status;
428 WERROR werr;
429 unsigned int orig_timeout;
430 struct dcerpc_binding_handle *b;
432 if (domain == NULL) {
433 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
434 r->in.domain_name, r->in.domain_guid,
435 r->in.site_name ? r->in.site_name : "",
436 r->in.flags,
437 r->out.dc_info);
440 status = cm_connect_netlogon(domain, &netlogon_pipe);
442 reset_cm_connection_on_error(domain, status);
443 if (!NT_STATUS_IS_OK(status)) {
444 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
445 return status;
448 b = netlogon_pipe->binding_handle;
450 /* This call can take a long time - allow the server to time out.
451 35 seconds should do it. */
453 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
455 if (domain->active_directory) {
456 status = dcerpc_netr_DsRGetDCName(b,
457 p->mem_ctx, domain->dcname,
458 r->in.domain_name, NULL, r->in.domain_guid,
459 r->in.flags, r->out.dc_info, &werr);
460 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
461 goto done;
463 if (reset_cm_connection_on_error(domain, status)) {
464 /* Re-initialize. */
465 status = cm_connect_netlogon(domain, &netlogon_pipe);
467 reset_cm_connection_on_error(domain, status);
468 if (!NT_STATUS_IS_OK(status)) {
469 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
470 return status;
473 b = netlogon_pipe->binding_handle;
475 /* This call can take a long time - allow the server to time out.
476 35 seconds should do it. */
478 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
483 * Fallback to less capable methods
486 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
487 if (dc_info == NULL) {
488 status = NT_STATUS_NO_MEMORY;
489 goto done;
492 if (r->in.flags & DS_PDC_REQUIRED) {
493 status = dcerpc_netr_GetDcName(b,
494 p->mem_ctx, domain->dcname,
495 r->in.domain_name, &dc_info->dc_unc, &werr);
496 } else {
497 status = dcerpc_netr_GetAnyDCName(b,
498 p->mem_ctx, domain->dcname,
499 r->in.domain_name, &dc_info->dc_unc, &werr);
502 reset_cm_connection_on_error(domain, status);
503 if (!NT_STATUS_IS_OK(status)) {
504 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
505 nt_errstr(status)));
506 goto done;
508 if (!W_ERROR_IS_OK(werr)) {
509 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
510 win_errstr(werr)));
511 status = werror_to_ntstatus(werr);
512 goto done;
515 *r->out.dc_info = dc_info;
516 status = NT_STATUS_OK;
518 done:
519 /* And restore our original timeout. */
520 rpccli_set_timeout(netlogon_pipe, orig_timeout);
522 return status;
525 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
527 struct winbindd_domain *domain = wb_child_domain();
528 char *domain_name;
529 char **names;
530 enum lsa_SidType *types;
531 struct wbint_Principal *result;
532 NTSTATUS status;
533 int i;
535 if (domain == NULL) {
536 return NT_STATUS_REQUEST_NOT_ACCEPTED;
539 status = domain->methods->rids_to_names(
540 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
541 r->in.rids->num_rids, &domain_name, &names, &types);
542 reset_cm_connection_on_error(domain, status);
543 if (!NT_STATUS_IS_OK(status)) {
544 return status;
547 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
549 result = talloc_array(p->mem_ctx, struct wbint_Principal,
550 r->in.rids->num_rids);
551 if (result == NULL) {
552 return NT_STATUS_NO_MEMORY;
555 for (i=0; i<r->in.rids->num_rids; i++) {
556 sid_compose(&result[i].sid, r->in.domain_sid,
557 r->in.rids->rids[i]);
558 result[i].type = types[i];
559 result[i].name = talloc_move(result, &names[i]);
561 TALLOC_FREE(types);
562 TALLOC_FREE(names);
564 r->out.names->num_principals = r->in.rids->num_rids;
565 r->out.names->principals = result;
566 return NT_STATUS_OK;
569 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
570 struct wbint_CheckMachineAccount *r)
572 struct winbindd_domain *domain;
573 int num_retries = 0;
574 NTSTATUS status;
576 domain = wb_child_domain();
577 if (domain == NULL) {
578 return NT_STATUS_REQUEST_NOT_ACCEPTED;
581 again:
582 invalidate_cm_connection(&domain->conn);
583 domain->conn.netlogon_force_reauth = true;
586 struct rpc_pipe_client *netlogon_pipe;
587 status = cm_connect_netlogon(domain, &netlogon_pipe);
590 /* There is a race condition between fetching the trust account
591 password and the periodic machine password change. So it's
592 possible that the trust account password has been changed on us.
593 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
595 #define MAX_RETRIES 3
597 if ((num_retries < MAX_RETRIES)
598 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
599 num_retries++;
600 goto again;
603 if (!NT_STATUS_IS_OK(status)) {
604 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
605 goto done;
608 /* Pass back result code - zero for success, other values for
609 specific failures. */
611 DEBUG(3,("domain %s secret is %s\n", domain->name,
612 NT_STATUS_IS_OK(status) ? "good" : "bad"));
614 done:
615 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
616 ("Checking the trust account password for domain %s returned %s\n",
617 domain->name, nt_errstr(status)));
619 return status;
622 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
623 struct wbint_ChangeMachineAccount *r)
625 struct messaging_context *msg_ctx = winbind_messaging_context();
626 struct winbindd_domain *domain;
627 NTSTATUS status;
628 struct rpc_pipe_client *netlogon_pipe;
630 domain = wb_child_domain();
631 if (domain == NULL) {
632 return NT_STATUS_REQUEST_NOT_ACCEPTED;
635 status = cm_connect_netlogon(domain, &netlogon_pipe);
636 if (!NT_STATUS_IS_OK(status)) {
637 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
638 goto done;
641 status = trust_pw_change(domain->conn.netlogon_creds,
642 msg_ctx,
643 netlogon_pipe->binding_handle,
644 domain->name,
645 true); /* force */
647 /* Pass back result code - zero for success, other values for
648 specific failures. */
650 DEBUG(3,("domain %s secret %s\n", domain->name,
651 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
653 done:
654 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
655 ("Changing the trust account password for domain %s returned %s\n",
656 domain->name, nt_errstr(status)));
658 return status;
661 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
663 NTSTATUS status;
664 struct winbindd_domain *domain;
665 struct rpc_pipe_client *netlogon_pipe;
666 union netr_CONTROL_QUERY_INFORMATION info;
667 WERROR werr;
668 fstring logon_server;
669 struct dcerpc_binding_handle *b;
671 domain = wb_child_domain();
672 if (domain == NULL) {
673 return NT_STATUS_REQUEST_NOT_ACCEPTED;
676 status = cm_connect_netlogon(domain, &netlogon_pipe);
677 reset_cm_connection_on_error(domain, status);
678 if (!NT_STATUS_IS_OK(status)) {
679 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
680 nt_errstr(status)));
681 return status;
684 b = netlogon_pipe->binding_handle;
686 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
687 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
688 if (*r->out.dcname == NULL) {
689 DEBUG(2, ("Could not allocate memory\n"));
690 return NT_STATUS_NO_MEMORY;
694 * This provokes a WERR_NOT_SUPPORTED error message. This is
695 * documented in the wspp docs. I could not get a successful
696 * call to work, but the main point here is testing that the
697 * netlogon pipe works.
699 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
700 logon_server, NETLOGON_CONTROL_QUERY,
701 2, &info, &werr);
703 reset_cm_connection_on_error(domain, status);
704 if (!NT_STATUS_IS_OK(status)) {
705 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
706 nt_errstr(status)));
707 return status;
710 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
711 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
712 "WERR_NOT_SUPPORTED\n",
713 win_errstr(werr)));
714 return werror_to_ntstatus(werr);
717 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
718 return NT_STATUS_OK;