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",
218 for (j=0; j<num_ids; j++) {
219 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
221 if (ids[j].status != ID_MAPPED) {
224 id->unix_id = ids[j].xid.id;
227 status = NT_STATUS_OK;
230 TALLOC_FREE(id_ptrs);
236 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
238 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
239 r->out.sid, r->in.uid);
242 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
244 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
245 r->out.sid, r->in.gid);
248 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
253 status = idmap_allocate_uid(&xid);
254 if (!NT_STATUS_IS_OK(status)) {
257 *r->out.uid = xid.id;
261 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
266 status = idmap_allocate_gid(&xid);
267 if (!NT_STATUS_IS_OK(status)) {
270 *r->out.gid = xid.id;
274 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
276 struct winbindd_domain *domain = wb_child_domain();
279 if (domain == NULL) {
280 return NT_STATUS_REQUEST_NOT_ACCEPTED;
283 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
285 reset_cm_connection_on_error(domain, status);
289 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
290 struct wbint_LookupUserAliases *r)
292 struct winbindd_domain *domain = wb_child_domain();
295 if (domain == NULL) {
296 return NT_STATUS_REQUEST_NOT_ACCEPTED;
299 status = domain->methods->lookup_useraliases(
300 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
301 &r->out.rids->num_rids, &r->out.rids->rids);
302 reset_cm_connection_on_error(domain, status);
306 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
307 struct wbint_LookupUserGroups *r)
309 struct winbindd_domain *domain = wb_child_domain();
312 if (domain == NULL) {
313 return NT_STATUS_REQUEST_NOT_ACCEPTED;
316 status = domain->methods->lookup_usergroups(
317 domain, p->mem_ctx, r->in.sid,
318 &r->out.sids->num_sids, &r->out.sids->sids);
319 reset_cm_connection_on_error(domain, status);
323 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
324 struct wbint_QuerySequenceNumber *r)
326 struct winbindd_domain *domain = wb_child_domain();
329 if (domain == NULL) {
330 return NT_STATUS_REQUEST_NOT_ACCEPTED;
333 status = domain->methods->sequence_number(domain, r->out.sequence);
334 reset_cm_connection_on_error(domain, status);
338 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
339 struct wbint_LookupGroupMembers *r)
341 struct winbindd_domain *domain = wb_child_domain();
342 uint32_t i, num_names;
343 struct dom_sid *sid_mem;
345 uint32_t *name_types;
348 if (domain == NULL) {
349 return NT_STATUS_REQUEST_NOT_ACCEPTED;
352 status = domain->methods->lookup_groupmem(
353 domain, p->mem_ctx, r->in.sid, r->in.type,
354 &num_names, &sid_mem, &names, &name_types);
355 reset_cm_connection_on_error(domain, status);
356 if (!NT_STATUS_IS_OK(status)) {
360 r->out.members->num_principals = num_names;
361 r->out.members->principals = talloc_array(
362 r->out.members, struct wbint_Principal, num_names);
363 if (r->out.members->principals == NULL) {
364 return NT_STATUS_NO_MEMORY;
367 for (i=0; i<num_names; i++) {
368 struct wbint_Principal *m = &r->out.members->principals[i];
369 sid_copy(&m->sid, &sid_mem[i]);
370 m->name = talloc_move(r->out.members->principals, &names[i]);
371 m->type = (enum lsa_SidType)name_types[i];
377 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
378 struct wbint_QueryUserList *r)
380 struct winbindd_domain *domain = wb_child_domain();
383 if (domain == NULL) {
384 return NT_STATUS_REQUEST_NOT_ACCEPTED;
387 status = domain->methods->query_user_list(
388 domain, p->mem_ctx, &r->out.users->num_userinfos,
389 &r->out.users->userinfos);
390 reset_cm_connection_on_error(domain, status);
394 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
395 struct wbint_QueryGroupList *r)
397 struct winbindd_domain *domain = wb_child_domain();
398 uint32_t i, num_groups;
399 struct wb_acct_info *groups;
400 struct wbint_Principal *result;
403 if (domain == NULL) {
404 return NT_STATUS_REQUEST_NOT_ACCEPTED;
407 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
408 &num_groups, &groups);
409 reset_cm_connection_on_error(domain, status);
410 if (!NT_STATUS_IS_OK(status)) {
414 result = talloc_array(r->out.groups, struct wbint_Principal,
416 if (result == NULL) {
417 return NT_STATUS_NO_MEMORY;
420 for (i=0; i<num_groups; i++) {
421 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
422 result[i].type = SID_NAME_DOM_GRP;
423 result[i].name = talloc_strdup(result, groups[i].acct_name);
424 if (result[i].name == NULL) {
427 return NT_STATUS_NO_MEMORY;
431 r->out.groups->num_principals = num_groups;
432 r->out.groups->principals = result;
438 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
440 struct winbindd_domain *domain = wb_child_domain();
441 struct rpc_pipe_client *netlogon_pipe;
442 struct netr_DsRGetDCNameInfo *dc_info;
445 unsigned int orig_timeout;
446 struct dcerpc_binding_handle *b;
448 if (domain == NULL) {
449 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
450 r->in.domain_name, r->in.domain_guid,
451 r->in.site_name ? r->in.site_name : "",
456 status = cm_connect_netlogon(domain, &netlogon_pipe);
458 reset_cm_connection_on_error(domain, status);
459 if (!NT_STATUS_IS_OK(status)) {
460 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
464 b = netlogon_pipe->binding_handle;
466 /* This call can take a long time - allow the server to time out.
467 35 seconds should do it. */
469 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
471 if (domain->active_directory) {
472 status = dcerpc_netr_DsRGetDCName(b,
473 p->mem_ctx, domain->dcname,
474 r->in.domain_name, NULL, r->in.domain_guid,
475 r->in.flags, r->out.dc_info, &werr);
476 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
479 if (reset_cm_connection_on_error(domain, status)) {
481 status = cm_connect_netlogon(domain, &netlogon_pipe);
483 reset_cm_connection_on_error(domain, status);
484 if (!NT_STATUS_IS_OK(status)) {
485 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
489 b = netlogon_pipe->binding_handle;
491 /* This call can take a long time - allow the server to time out.
492 35 seconds should do it. */
494 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
499 * Fallback to less capable methods
502 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
503 if (dc_info == NULL) {
504 status = NT_STATUS_NO_MEMORY;
508 if (r->in.flags & DS_PDC_REQUIRED) {
509 status = dcerpc_netr_GetDcName(b,
510 p->mem_ctx, domain->dcname,
511 r->in.domain_name, &dc_info->dc_unc, &werr);
513 status = dcerpc_netr_GetAnyDCName(b,
514 p->mem_ctx, domain->dcname,
515 r->in.domain_name, &dc_info->dc_unc, &werr);
518 reset_cm_connection_on_error(domain, status);
519 if (!NT_STATUS_IS_OK(status)) {
520 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
524 if (!W_ERROR_IS_OK(werr)) {
525 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
527 status = werror_to_ntstatus(werr);
531 *r->out.dc_info = dc_info;
532 status = NT_STATUS_OK;
535 /* And restore our original timeout. */
536 rpccli_set_timeout(netlogon_pipe, orig_timeout);
541 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
543 struct winbindd_domain *domain = wb_child_domain();
546 enum lsa_SidType *types;
547 struct wbint_Principal *result;
551 if (domain == NULL) {
552 return NT_STATUS_REQUEST_NOT_ACCEPTED;
555 status = domain->methods->rids_to_names(
556 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
557 r->in.rids->num_rids, &domain_name, &names, &types);
558 reset_cm_connection_on_error(domain, status);
559 if (!NT_STATUS_IS_OK(status)) {
563 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
565 result = talloc_array(p->mem_ctx, struct wbint_Principal,
566 r->in.rids->num_rids);
567 if (result == NULL) {
568 return NT_STATUS_NO_MEMORY;
571 for (i=0; i<r->in.rids->num_rids; i++) {
572 sid_compose(&result[i].sid, r->in.domain_sid,
573 r->in.rids->rids[i]);
574 result[i].type = types[i];
575 result[i].name = talloc_move(result, &names[i]);
580 r->out.names->num_principals = r->in.rids->num_rids;
581 r->out.names->principals = result;
585 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
586 struct wbint_CheckMachineAccount *r)
588 struct winbindd_domain *domain;
592 domain = wb_child_domain();
593 if (domain == NULL) {
594 return NT_STATUS_REQUEST_NOT_ACCEPTED;
598 invalidate_cm_connection(&domain->conn);
601 struct rpc_pipe_client *netlogon_pipe;
602 status = cm_connect_netlogon(domain, &netlogon_pipe);
605 /* There is a race condition between fetching the trust account
606 password and the periodic machine password change. So it's
607 possible that the trust account password has been changed on us.
608 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
610 #define MAX_RETRIES 3
612 if ((num_retries < MAX_RETRIES)
613 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
618 if (!NT_STATUS_IS_OK(status)) {
619 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
623 /* Pass back result code - zero for success, other values for
624 specific failures. */
626 DEBUG(3,("domain %s secret is %s\n", domain->name,
627 NT_STATUS_IS_OK(status) ? "good" : "bad"));
630 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
631 ("Checking the trust account password for domain %s returned %s\n",
632 domain->name, nt_errstr(status)));
637 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
638 struct wbint_ChangeMachineAccount *r)
640 struct winbindd_domain *domain;
643 struct rpc_pipe_client *netlogon_pipe;
647 domain = wb_child_domain();
648 if (domain == NULL) {
649 return NT_STATUS_REQUEST_NOT_ACCEPTED;
652 invalidate_cm_connection(&domain->conn);
655 status = cm_connect_netlogon(domain, &netlogon_pipe);
658 /* There is a race condition between fetching the trust account
659 password and the periodic machine password change. So it's
660 possible that the trust account password has been changed on us.
661 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
663 #define MAX_RETRIES 3
665 if ((num_retries < MAX_RETRIES)
666 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
671 if (!NT_STATUS_IS_OK(status)) {
672 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
676 tmp_ctx = talloc_new(p->mem_ctx);
678 status = trust_pw_find_change_and_store_it(netlogon_pipe,
681 talloc_destroy(tmp_ctx);
683 /* Pass back result code - zero for success, other values for
684 specific failures. */
686 DEBUG(3,("domain %s secret %s\n", domain->name,
687 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
690 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
691 ("Changing the trust account password for domain %s returned %s\n",
692 domain->name, nt_errstr(status)));
697 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
700 struct winbindd_domain *domain;
701 struct rpc_pipe_client *netlogon_pipe;
702 union netr_CONTROL_QUERY_INFORMATION info;
704 fstring logon_server;
705 struct dcerpc_binding_handle *b;
707 domain = wb_child_domain();
708 if (domain == NULL) {
709 return NT_STATUS_REQUEST_NOT_ACCEPTED;
712 status = cm_connect_netlogon(domain, &netlogon_pipe);
713 reset_cm_connection_on_error(domain, status);
714 if (!NT_STATUS_IS_OK(status)) {
715 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
719 b = netlogon_pipe->binding_handle;
721 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
722 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
723 if (r->out.dcname == NULL) {
724 DEBUG(2, ("Could not allocate memory\n"));
725 return NT_STATUS_NO_MEMORY;
729 * This provokes a WERR_NOT_SUPPORTED error message. This is
730 * documented in the wspp docs. I could not get a successful
731 * call to work, but the main point here is testing that the
732 * netlogon pipe works.
734 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
735 logon_server, NETLOGON_CONTROL_QUERY,
738 reset_cm_connection_on_error(domain, status);
739 if (!NT_STATUS_IS_OK(status)) {
740 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
745 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
746 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
747 "WERR_NOT_SUPPORTED\n",
749 return werror_to_ntstatus(werr);
752 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));