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/>.
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
28 #include "librpc/gen_ndr/srv_wbint.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.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,
41 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
42 invalidate_cm_connection(&domain->conn);
43 /* We invalidated the connection. */
49 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
51 struct winbindd_domain *domain = wb_child_domain();
54 enum lsa_SidType type;
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)) {
68 *r->out.domain = dom_name;
74 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
76 struct winbindd_domain *domain = wb_child_domain();
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);
95 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
97 struct winbindd_domain *domain = wb_child_domain();
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);
111 NTSTATUS _wbint_Sid2Uid(struct pipes_struct *p, struct wbint_Sid2Uid *r)
116 status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
118 if (!NT_STATUS_IS_OK(status)) {
125 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
130 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
132 if (!NT_STATUS_IS_OK(status)) {
139 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
140 struct wbint_Sids2UnixIDs *r)
143 struct id_map *ids = NULL;
144 struct id_map **id_ptrs = NULL;
145 struct dom_sid *sids = NULL;
146 uint32_t *id_idx = NULL;
147 NTSTATUS status = NT_STATUS_NO_MEMORY;
149 for (i=0; i<r->in.domains->count; i++) {
150 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
151 struct idmap_domain *dom;
154 dom = idmap_find_domain(d->name.string);
156 DEBUG(10, ("idmap domain %s not found\n",
163 for (j=0; j<r->in.ids->num_ids; j++) {
164 if (r->in.ids->ids[j].domain_index == i) {
169 ids = talloc_realloc(talloc_tos(), ids,
170 struct id_map, num_ids);
174 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
175 struct id_map *, num_ids+1);
176 if (id_ptrs == NULL) {
179 id_idx = talloc_realloc(talloc_tos(), id_idx,
181 if (id_idx == NULL) {
184 sids = talloc_realloc(talloc_tos(), sids,
185 struct dom_sid, num_ids);
193 * Convert the input data into a list of
194 * id_map structs suitable for handing in
195 * to the idmap sids_to_unixids method.
197 for (j=0; j<r->in.ids->num_ids; j++) {
198 struct wbint_TransID *id = &r->in.ids->ids[j];
200 if (id->domain_index != i) {
204 id_ptrs[num_ids] = &ids[num_ids];
206 ids[num_ids].sid = &sids[num_ids];
207 sid_compose(ids[num_ids].sid, d->sid, id->rid);
208 ids[num_ids].xid.type = id->type;
209 ids[num_ids].status = ID_UNKNOWN;
212 id_ptrs[num_ids] = NULL;
214 status = dom->methods->sids_to_unixids(dom, id_ptrs);
215 DEBUG(10, ("sids_to_unixids returned %s\n",
219 * Extract the results for handing them back to the caller.
221 for (j=0; j<num_ids; j++) {
222 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
224 if (ids[j].status != ID_MAPPED) {
227 id->unix_id = ids[j].xid.id;
230 status = NT_STATUS_OK;
233 TALLOC_FREE(id_ptrs);
239 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
241 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
242 r->out.sid, r->in.uid);
245 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
247 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
248 r->out.sid, r->in.gid);
251 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
256 status = idmap_allocate_uid(&xid);
257 if (!NT_STATUS_IS_OK(status)) {
260 *r->out.uid = xid.id;
264 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
269 status = idmap_allocate_gid(&xid);
270 if (!NT_STATUS_IS_OK(status)) {
273 *r->out.gid = xid.id;
277 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
279 struct winbindd_domain *domain = wb_child_domain();
282 if (domain == NULL) {
283 return NT_STATUS_REQUEST_NOT_ACCEPTED;
286 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
288 reset_cm_connection_on_error(domain, status);
292 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
293 struct wbint_LookupUserAliases *r)
295 struct winbindd_domain *domain = wb_child_domain();
298 if (domain == NULL) {
299 return NT_STATUS_REQUEST_NOT_ACCEPTED;
302 status = domain->methods->lookup_useraliases(
303 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
304 &r->out.rids->num_rids, &r->out.rids->rids);
305 reset_cm_connection_on_error(domain, status);
309 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
310 struct wbint_LookupUserGroups *r)
312 struct winbindd_domain *domain = wb_child_domain();
315 if (domain == NULL) {
316 return NT_STATUS_REQUEST_NOT_ACCEPTED;
319 status = domain->methods->lookup_usergroups(
320 domain, p->mem_ctx, r->in.sid,
321 &r->out.sids->num_sids, &r->out.sids->sids);
322 reset_cm_connection_on_error(domain, status);
326 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
327 struct wbint_QuerySequenceNumber *r)
329 struct winbindd_domain *domain = wb_child_domain();
332 if (domain == NULL) {
333 return NT_STATUS_REQUEST_NOT_ACCEPTED;
336 status = domain->methods->sequence_number(domain, r->out.sequence);
337 reset_cm_connection_on_error(domain, status);
341 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
342 struct wbint_LookupGroupMembers *r)
344 struct winbindd_domain *domain = wb_child_domain();
345 uint32_t i, num_names;
346 struct dom_sid *sid_mem;
348 uint32_t *name_types;
351 if (domain == NULL) {
352 return NT_STATUS_REQUEST_NOT_ACCEPTED;
355 status = domain->methods->lookup_groupmem(
356 domain, p->mem_ctx, r->in.sid, r->in.type,
357 &num_names, &sid_mem, &names, &name_types);
358 reset_cm_connection_on_error(domain, status);
359 if (!NT_STATUS_IS_OK(status)) {
363 r->out.members->num_principals = num_names;
364 r->out.members->principals = talloc_array(
365 r->out.members, struct wbint_Principal, num_names);
366 if (r->out.members->principals == NULL) {
367 return NT_STATUS_NO_MEMORY;
370 for (i=0; i<num_names; i++) {
371 struct wbint_Principal *m = &r->out.members->principals[i];
372 sid_copy(&m->sid, &sid_mem[i]);
373 m->name = talloc_move(r->out.members->principals, &names[i]);
374 m->type = (enum lsa_SidType)name_types[i];
380 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
381 struct wbint_QueryUserList *r)
383 struct winbindd_domain *domain = wb_child_domain();
386 if (domain == NULL) {
387 return NT_STATUS_REQUEST_NOT_ACCEPTED;
390 status = domain->methods->query_user_list(
391 domain, p->mem_ctx, &r->out.users->num_userinfos,
392 &r->out.users->userinfos);
393 reset_cm_connection_on_error(domain, status);
397 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
398 struct wbint_QueryGroupList *r)
400 struct winbindd_domain *domain = wb_child_domain();
401 uint32_t i, num_groups;
402 struct wb_acct_info *groups;
403 struct wbint_Principal *result;
406 if (domain == NULL) {
407 return NT_STATUS_REQUEST_NOT_ACCEPTED;
410 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
411 &num_groups, &groups);
412 reset_cm_connection_on_error(domain, status);
413 if (!NT_STATUS_IS_OK(status)) {
417 result = talloc_array(r->out.groups, struct wbint_Principal,
419 if (result == NULL) {
420 return NT_STATUS_NO_MEMORY;
423 for (i=0; i<num_groups; i++) {
424 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
425 result[i].type = SID_NAME_DOM_GRP;
426 result[i].name = talloc_strdup(result, groups[i].acct_name);
427 if (result[i].name == NULL) {
430 return NT_STATUS_NO_MEMORY;
434 r->out.groups->num_principals = num_groups;
435 r->out.groups->principals = result;
441 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
443 struct winbindd_domain *domain = wb_child_domain();
444 struct rpc_pipe_client *netlogon_pipe;
445 struct netr_DsRGetDCNameInfo *dc_info;
448 unsigned int orig_timeout;
449 struct dcerpc_binding_handle *b;
451 if (domain == NULL) {
452 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
453 r->in.domain_name, r->in.domain_guid,
454 r->in.site_name ? r->in.site_name : "",
459 status = cm_connect_netlogon(domain, &netlogon_pipe);
461 reset_cm_connection_on_error(domain, status);
462 if (!NT_STATUS_IS_OK(status)) {
463 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
467 b = netlogon_pipe->binding_handle;
469 /* This call can take a long time - allow the server to time out.
470 35 seconds should do it. */
472 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
474 if (domain->active_directory) {
475 status = dcerpc_netr_DsRGetDCName(b,
476 p->mem_ctx, domain->dcname,
477 r->in.domain_name, NULL, r->in.domain_guid,
478 r->in.flags, r->out.dc_info, &werr);
479 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
482 if (reset_cm_connection_on_error(domain, status)) {
484 status = cm_connect_netlogon(domain, &netlogon_pipe);
486 reset_cm_connection_on_error(domain, status);
487 if (!NT_STATUS_IS_OK(status)) {
488 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
492 b = netlogon_pipe->binding_handle;
494 /* This call can take a long time - allow the server to time out.
495 35 seconds should do it. */
497 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
502 * Fallback to less capable methods
505 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
506 if (dc_info == NULL) {
507 status = NT_STATUS_NO_MEMORY;
511 if (r->in.flags & DS_PDC_REQUIRED) {
512 status = dcerpc_netr_GetDcName(b,
513 p->mem_ctx, domain->dcname,
514 r->in.domain_name, &dc_info->dc_unc, &werr);
516 status = dcerpc_netr_GetAnyDCName(b,
517 p->mem_ctx, domain->dcname,
518 r->in.domain_name, &dc_info->dc_unc, &werr);
521 reset_cm_connection_on_error(domain, status);
522 if (!NT_STATUS_IS_OK(status)) {
523 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
527 if (!W_ERROR_IS_OK(werr)) {
528 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
530 status = werror_to_ntstatus(werr);
534 *r->out.dc_info = dc_info;
535 status = NT_STATUS_OK;
538 /* And restore our original timeout. */
539 rpccli_set_timeout(netlogon_pipe, orig_timeout);
544 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
546 struct winbindd_domain *domain = wb_child_domain();
549 enum lsa_SidType *types;
550 struct wbint_Principal *result;
554 if (domain == NULL) {
555 return NT_STATUS_REQUEST_NOT_ACCEPTED;
558 status = domain->methods->rids_to_names(
559 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
560 r->in.rids->num_rids, &domain_name, &names, &types);
561 reset_cm_connection_on_error(domain, status);
562 if (!NT_STATUS_IS_OK(status)) {
566 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
568 result = talloc_array(p->mem_ctx, struct wbint_Principal,
569 r->in.rids->num_rids);
570 if (result == NULL) {
571 return NT_STATUS_NO_MEMORY;
574 for (i=0; i<r->in.rids->num_rids; i++) {
575 sid_compose(&result[i].sid, r->in.domain_sid,
576 r->in.rids->rids[i]);
577 result[i].type = types[i];
578 result[i].name = talloc_move(result, &names[i]);
583 r->out.names->num_principals = r->in.rids->num_rids;
584 r->out.names->principals = result;
588 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
589 struct wbint_CheckMachineAccount *r)
591 struct winbindd_domain *domain;
595 domain = wb_child_domain();
596 if (domain == NULL) {
597 return NT_STATUS_REQUEST_NOT_ACCEPTED;
601 invalidate_cm_connection(&domain->conn);
604 struct rpc_pipe_client *netlogon_pipe;
605 status = cm_connect_netlogon(domain, &netlogon_pipe);
608 /* There is a race condition between fetching the trust account
609 password and the periodic machine password change. So it's
610 possible that the trust account password has been changed on us.
611 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
613 #define MAX_RETRIES 3
615 if ((num_retries < MAX_RETRIES)
616 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
621 if (!NT_STATUS_IS_OK(status)) {
622 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
626 /* Pass back result code - zero for success, other values for
627 specific failures. */
629 DEBUG(3,("domain %s secret is %s\n", domain->name,
630 NT_STATUS_IS_OK(status) ? "good" : "bad"));
633 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
634 ("Checking the trust account password for domain %s returned %s\n",
635 domain->name, nt_errstr(status)));
640 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
641 struct wbint_ChangeMachineAccount *r)
643 struct winbindd_domain *domain;
646 struct rpc_pipe_client *netlogon_pipe;
650 domain = wb_child_domain();
651 if (domain == NULL) {
652 return NT_STATUS_REQUEST_NOT_ACCEPTED;
655 invalidate_cm_connection(&domain->conn);
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)) {
674 if (!NT_STATUS_IS_OK(status)) {
675 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
679 tmp_ctx = talloc_new(p->mem_ctx);
681 status = trust_pw_find_change_and_store_it(netlogon_pipe,
684 talloc_destroy(tmp_ctx);
686 /* Pass back result code - zero for success, other values for
687 specific failures. */
689 DEBUG(3,("domain %s secret %s\n", domain->name,
690 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
693 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
694 ("Changing the trust account password for domain %s returned %s\n",
695 domain->name, nt_errstr(status)));
700 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
703 struct winbindd_domain *domain;
704 struct rpc_pipe_client *netlogon_pipe;
705 union netr_CONTROL_QUERY_INFORMATION info;
707 fstring logon_server;
708 struct dcerpc_binding_handle *b;
710 domain = wb_child_domain();
711 if (domain == NULL) {
712 return NT_STATUS_REQUEST_NOT_ACCEPTED;
715 status = cm_connect_netlogon(domain, &netlogon_pipe);
716 reset_cm_connection_on_error(domain, status);
717 if (!NT_STATUS_IS_OK(status)) {
718 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
722 b = netlogon_pipe->binding_handle;
724 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
725 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
726 if (r->out.dcname == NULL) {
727 DEBUG(2, ("Could not allocate memory\n"));
728 return NT_STATUS_NO_MEMORY;
732 * This provokes a WERR_NOT_SUPPORTED error message. This is
733 * documented in the wspp docs. I could not get a successful
734 * call to work, but the main point here is testing that the
735 * netlogon pipe works.
737 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
738 logon_server, NETLOGON_CONTROL_QUERY,
741 reset_cm_connection_on_error(domain, status);
742 if (!NT_STATUS_IS_OK(status)) {
743 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
748 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
749 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
750 "WERR_NOT_SUPPORTED\n",
752 return werror_to_ntstatus(werr);
755 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));