s3:winbindd: remove unused server implementation of wbint_Sid2Uid()
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob914647e800b97bbc9c58742526fb821f6255102d
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 NTSTATUS status;
79 if (domain == NULL) {
80 return NT_STATUS_REQUEST_NOT_ACCEPTED;
84 * This breaks the winbindd_domain->methods abstraction: This
85 * is only called for remote domains, and both winbindd_msrpc
86 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
87 * done at the wbint RPC layer.
89 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
90 &r->out.domains, &r->out.names);
91 reset_cm_connection_on_error(domain, status);
92 return status;
95 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
97 struct winbindd_domain *domain = wb_child_domain();
98 NTSTATUS status;
100 if (domain == NULL) {
101 return NT_STATUS_REQUEST_NOT_ACCEPTED;
104 status = domain->methods->name_to_sid(
105 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
106 r->out.sid, r->out.type);
107 reset_cm_connection_on_error(domain, status);
108 return status;
111 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
113 gid_t gid;
114 NTSTATUS status;
116 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
117 r->in.sid, &gid);
118 if (!NT_STATUS_IS_OK(status)) {
119 return status;
121 *r->out.gid = gid;
122 return NT_STATUS_OK;
125 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
126 struct wbint_Sids2UnixIDs *r)
128 uint32_t i, j;
129 struct id_map *ids = NULL;
130 struct id_map **id_ptrs = NULL;
131 struct dom_sid *sids = NULL;
132 uint32_t *id_idx = NULL;
133 NTSTATUS status = NT_STATUS_NO_MEMORY;
135 for (i=0; i<r->in.domains->count; i++) {
136 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
137 struct idmap_domain *dom;
138 uint32_t num_ids;
140 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
141 if (dom == NULL) {
142 DEBUG(10, ("idmap domain %s:%s not found\n",
143 d->name.string, sid_string_dbg(d->sid)));
144 continue;
147 num_ids = 0;
149 for (j=0; j<r->in.ids->num_ids; j++) {
150 if (r->in.ids->ids[j].domain_index == i) {
151 num_ids += 1;
155 ids = talloc_realloc(talloc_tos(), ids,
156 struct id_map, num_ids);
157 if (ids == NULL) {
158 goto nomem;
160 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
161 struct id_map *, num_ids+1);
162 if (id_ptrs == NULL) {
163 goto nomem;
165 id_idx = talloc_realloc(talloc_tos(), id_idx,
166 uint32_t, num_ids);
167 if (id_idx == NULL) {
168 goto nomem;
170 sids = talloc_realloc(talloc_tos(), sids,
171 struct dom_sid, num_ids);
172 if (sids == NULL) {
173 goto nomem;
176 num_ids = 0;
179 * Convert the input data into a list of
180 * id_map structs suitable for handing in
181 * to the idmap sids_to_unixids method.
183 for (j=0; j<r->in.ids->num_ids; j++) {
184 struct wbint_TransID *id = &r->in.ids->ids[j];
186 if (id->domain_index != i) {
187 continue;
189 id_idx[num_ids] = j;
190 id_ptrs[num_ids] = &ids[num_ids];
192 ids[num_ids].sid = &sids[num_ids];
193 sid_compose(ids[num_ids].sid, d->sid, id->rid);
194 ids[num_ids].xid.type = id->type;
195 ids[num_ids].status = ID_UNKNOWN;
196 num_ids += 1;
198 id_ptrs[num_ids] = NULL;
200 status = dom->methods->sids_to_unixids(dom, id_ptrs);
201 DEBUG(10, ("sids_to_unixids returned %s\n",
202 nt_errstr(status)));
205 * Extract the results for handing them back to the caller.
207 for (j=0; j<num_ids; j++) {
208 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
210 if (ids[j].status != ID_MAPPED) {
211 id->xid.id = UINT32_MAX;
212 id->xid.type = ID_TYPE_NOT_SPECIFIED;
213 continue;
216 id->xid = ids[j].xid;
219 status = NT_STATUS_OK;
220 nomem:
221 TALLOC_FREE(ids);
222 TALLOC_FREE(id_ptrs);
223 TALLOC_FREE(id_idx);
224 TALLOC_FREE(sids);
225 return status;
228 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
230 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
231 r->out.sid, r->in.uid);
234 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
236 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
237 r->out.sid, r->in.gid);
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, num_groups;
391 struct wb_acct_info *groups;
392 struct wbint_Principal *result;
393 NTSTATUS status;
395 if (domain == NULL) {
396 return NT_STATUS_REQUEST_NOT_ACCEPTED;
399 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
400 &num_groups, &groups);
401 reset_cm_connection_on_error(domain, status);
402 if (!NT_STATUS_IS_OK(status)) {
403 return status;
406 result = talloc_array(r->out.groups, struct wbint_Principal,
407 num_groups);
408 if (result == NULL) {
409 return NT_STATUS_NO_MEMORY;
412 for (i=0; i<num_groups; i++) {
413 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
414 result[i].type = SID_NAME_DOM_GRP;
415 result[i].name = talloc_strdup(result, groups[i].acct_name);
416 if (result[i].name == NULL) {
417 TALLOC_FREE(result);
418 TALLOC_FREE(groups);
419 return NT_STATUS_NO_MEMORY;
423 r->out.groups->num_principals = num_groups;
424 r->out.groups->principals = result;
426 TALLOC_FREE(groups);
427 return NT_STATUS_OK;
430 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
432 struct winbindd_domain *domain = wb_child_domain();
433 struct rpc_pipe_client *netlogon_pipe;
434 struct netr_DsRGetDCNameInfo *dc_info;
435 NTSTATUS status;
436 WERROR werr;
437 unsigned int orig_timeout;
438 struct dcerpc_binding_handle *b;
440 if (domain == NULL) {
441 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
442 r->in.domain_name, r->in.domain_guid,
443 r->in.site_name ? r->in.site_name : "",
444 r->in.flags,
445 r->out.dc_info);
448 status = cm_connect_netlogon(domain, &netlogon_pipe);
450 reset_cm_connection_on_error(domain, status);
451 if (!NT_STATUS_IS_OK(status)) {
452 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
453 return status;
456 b = netlogon_pipe->binding_handle;
458 /* This call can take a long time - allow the server to time out.
459 35 seconds should do it. */
461 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
463 if (domain->active_directory) {
464 status = dcerpc_netr_DsRGetDCName(b,
465 p->mem_ctx, domain->dcname,
466 r->in.domain_name, NULL, r->in.domain_guid,
467 r->in.flags, r->out.dc_info, &werr);
468 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
469 goto done;
471 if (reset_cm_connection_on_error(domain, status)) {
472 /* Re-initialize. */
473 status = cm_connect_netlogon(domain, &netlogon_pipe);
475 reset_cm_connection_on_error(domain, status);
476 if (!NT_STATUS_IS_OK(status)) {
477 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
478 return status;
481 b = netlogon_pipe->binding_handle;
483 /* This call can take a long time - allow the server to time out.
484 35 seconds should do it. */
486 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
491 * Fallback to less capable methods
494 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
495 if (dc_info == NULL) {
496 status = NT_STATUS_NO_MEMORY;
497 goto done;
500 if (r->in.flags & DS_PDC_REQUIRED) {
501 status = dcerpc_netr_GetDcName(b,
502 p->mem_ctx, domain->dcname,
503 r->in.domain_name, &dc_info->dc_unc, &werr);
504 } else {
505 status = dcerpc_netr_GetAnyDCName(b,
506 p->mem_ctx, domain->dcname,
507 r->in.domain_name, &dc_info->dc_unc, &werr);
510 reset_cm_connection_on_error(domain, status);
511 if (!NT_STATUS_IS_OK(status)) {
512 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
513 nt_errstr(status)));
514 goto done;
516 if (!W_ERROR_IS_OK(werr)) {
517 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
518 win_errstr(werr)));
519 status = werror_to_ntstatus(werr);
520 goto done;
523 *r->out.dc_info = dc_info;
524 status = NT_STATUS_OK;
526 done:
527 /* And restore our original timeout. */
528 rpccli_set_timeout(netlogon_pipe, orig_timeout);
530 return status;
533 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
535 struct winbindd_domain *domain = wb_child_domain();
536 char *domain_name;
537 char **names;
538 enum lsa_SidType *types;
539 struct wbint_Principal *result;
540 NTSTATUS status;
541 int i;
543 if (domain == NULL) {
544 return NT_STATUS_REQUEST_NOT_ACCEPTED;
547 status = domain->methods->rids_to_names(
548 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
549 r->in.rids->num_rids, &domain_name, &names, &types);
550 reset_cm_connection_on_error(domain, status);
551 if (!NT_STATUS_IS_OK(status)) {
552 return status;
555 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
557 result = talloc_array(p->mem_ctx, struct wbint_Principal,
558 r->in.rids->num_rids);
559 if (result == NULL) {
560 return NT_STATUS_NO_MEMORY;
563 for (i=0; i<r->in.rids->num_rids; i++) {
564 sid_compose(&result[i].sid, r->in.domain_sid,
565 r->in.rids->rids[i]);
566 result[i].type = types[i];
567 result[i].name = talloc_move(result, &names[i]);
569 TALLOC_FREE(types);
570 TALLOC_FREE(names);
572 r->out.names->num_principals = r->in.rids->num_rids;
573 r->out.names->principals = result;
574 return NT_STATUS_OK;
577 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
578 struct wbint_CheckMachineAccount *r)
580 struct winbindd_domain *domain;
581 int num_retries = 0;
582 NTSTATUS status;
584 domain = wb_child_domain();
585 if (domain == NULL) {
586 return NT_STATUS_REQUEST_NOT_ACCEPTED;
589 again:
590 invalidate_cm_connection(&domain->conn);
593 struct rpc_pipe_client *netlogon_pipe;
594 status = cm_connect_netlogon(domain, &netlogon_pipe);
597 /* There is a race condition between fetching the trust account
598 password and the periodic machine password change. So it's
599 possible that the trust account password has been changed on us.
600 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
602 #define MAX_RETRIES 3
604 if ((num_retries < MAX_RETRIES)
605 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
606 num_retries++;
607 goto again;
610 if (!NT_STATUS_IS_OK(status)) {
611 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
612 goto done;
615 /* Pass back result code - zero for success, other values for
616 specific failures. */
618 DEBUG(3,("domain %s secret is %s\n", domain->name,
619 NT_STATUS_IS_OK(status) ? "good" : "bad"));
621 done:
622 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
623 ("Checking the trust account password for domain %s returned %s\n",
624 domain->name, nt_errstr(status)));
626 return status;
629 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
630 struct wbint_ChangeMachineAccount *r)
632 struct winbindd_domain *domain;
633 int num_retries = 0;
634 NTSTATUS status;
635 struct rpc_pipe_client *netlogon_pipe;
636 TALLOC_CTX *tmp_ctx;
638 again:
639 domain = wb_child_domain();
640 if (domain == NULL) {
641 return NT_STATUS_REQUEST_NOT_ACCEPTED;
644 invalidate_cm_connection(&domain->conn);
647 status = cm_connect_netlogon(domain, &netlogon_pipe);
650 /* There is a race condition between fetching the trust account
651 password and the periodic machine password change. So it's
652 possible that the trust account password has been changed on us.
653 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
655 #define MAX_RETRIES 3
657 if ((num_retries < MAX_RETRIES)
658 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
659 num_retries++;
660 goto again;
663 if (!NT_STATUS_IS_OK(status)) {
664 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
665 goto done;
668 tmp_ctx = talloc_new(p->mem_ctx);
670 status = trust_pw_find_change_and_store_it(netlogon_pipe,
671 tmp_ctx,
672 domain->name);
673 talloc_destroy(tmp_ctx);
675 /* Pass back result code - zero for success, other values for
676 specific failures. */
678 DEBUG(3,("domain %s secret %s\n", domain->name,
679 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
681 done:
682 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
683 ("Changing the trust account password for domain %s returned %s\n",
684 domain->name, nt_errstr(status)));
686 return status;
689 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
691 NTSTATUS status;
692 struct winbindd_domain *domain;
693 struct rpc_pipe_client *netlogon_pipe;
694 union netr_CONTROL_QUERY_INFORMATION info;
695 WERROR werr;
696 fstring logon_server;
697 struct dcerpc_binding_handle *b;
699 domain = wb_child_domain();
700 if (domain == NULL) {
701 return NT_STATUS_REQUEST_NOT_ACCEPTED;
704 status = cm_connect_netlogon(domain, &netlogon_pipe);
705 reset_cm_connection_on_error(domain, status);
706 if (!NT_STATUS_IS_OK(status)) {
707 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
708 return status;
711 b = netlogon_pipe->binding_handle;
713 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
714 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
715 if (r->out.dcname == NULL) {
716 DEBUG(2, ("Could not allocate memory\n"));
717 return NT_STATUS_NO_MEMORY;
721 * This provokes a WERR_NOT_SUPPORTED error message. This is
722 * documented in the wspp docs. I could not get a successful
723 * call to work, but the main point here is testing that the
724 * netlogon pipe works.
726 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
727 logon_server, NETLOGON_CONTROL_QUERY,
728 2, &info, &werr);
730 reset_cm_connection_on_error(domain, status);
731 if (!NT_STATUS_IS_OK(status)) {
732 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
733 nt_errstr(status)));
734 return status;
737 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
738 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
739 "WERR_NOT_SUPPORTED\n",
740 win_errstr(werr)));
741 return werror_to_ntstatus(werr);
744 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
745 return NT_STATUS_OK;