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_Sid2Gid(struct pipes_struct
*p
, struct wbint_Sid2Gid
*r
)
116 status
= idmap_sid_to_gid(r
->in
.dom_name
? r
->in
.dom_name
: "",
118 if (!NT_STATUS_IS_OK(status
)) {
125 NTSTATUS
_wbint_Sids2UnixIDs(struct pipes_struct
*p
,
126 struct wbint_Sids2UnixIDs
*r
)
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
;
140 dom
= idmap_find_domain_with_sid(d
->name
.string
, d
->sid
);
142 DEBUG(10, ("idmap domain %s:%s not found\n",
143 d
->name
.string
, sid_string_dbg(d
->sid
)));
149 for (j
=0; j
<r
->in
.ids
->num_ids
; j
++) {
150 if (r
->in
.ids
->ids
[j
].domain_index
== i
) {
155 ids
= talloc_realloc(talloc_tos(), ids
,
156 struct id_map
, num_ids
);
160 id_ptrs
= talloc_realloc(talloc_tos(), id_ptrs
,
161 struct id_map
*, num_ids
+1);
162 if (id_ptrs
== NULL
) {
165 id_idx
= talloc_realloc(talloc_tos(), id_idx
,
167 if (id_idx
== NULL
) {
170 sids
= talloc_realloc(talloc_tos(), sids
,
171 struct dom_sid
, num_ids
);
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
) {
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
;
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",
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
;
216 id
->xid
= ids
[j
].xid
;
219 status
= NT_STATUS_OK
;
222 TALLOC_FREE(id_ptrs
);
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
)
245 status
= idmap_allocate_uid(&xid
);
246 if (!NT_STATUS_IS_OK(status
)) {
249 *r
->out
.uid
= xid
.id
;
253 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
258 status
= idmap_allocate_gid(&xid
);
259 if (!NT_STATUS_IS_OK(status
)) {
262 *r
->out
.gid
= xid
.id
;
266 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
268 struct winbindd_domain
*domain
= wb_child_domain();
271 if (domain
== NULL
) {
272 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
275 status
= domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
277 reset_cm_connection_on_error(domain
, status
);
281 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
282 struct wbint_LookupUserAliases
*r
)
284 struct winbindd_domain
*domain
= wb_child_domain();
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
);
298 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
299 struct wbint_LookupUserGroups
*r
)
301 struct winbindd_domain
*domain
= wb_child_domain();
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
);
315 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
316 struct wbint_QuerySequenceNumber
*r
)
318 struct winbindd_domain
*domain
= wb_child_domain();
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
);
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
;
337 uint32_t *name_types
;
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
)) {
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
];
369 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
370 struct wbint_QueryUserList
*r
)
372 struct winbindd_domain
*domain
= wb_child_domain();
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
);
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
;
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
)) {
406 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
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
) {
419 return NT_STATUS_NO_MEMORY
;
423 r
->out
.groups
->num_principals
= num_groups
;
424 r
->out
.groups
->principals
= result
;
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
;
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
: "",
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"));
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
)) {
471 if (reset_cm_connection_on_error(domain
, status
)) {
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"));
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
;
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
);
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",
516 if (!W_ERROR_IS_OK(werr
)) {
517 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
519 status
= werror_to_ntstatus(werr
);
523 *r
->out
.dc_info
= dc_info
;
524 status
= NT_STATUS_OK
;
527 /* And restore our original timeout. */
528 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
533 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
535 struct winbindd_domain
*domain
= wb_child_domain();
538 enum lsa_SidType
*types
;
539 struct wbint_Principal
*result
;
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
)) {
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
]);
572 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
573 r
->out
.names
->principals
= result
;
577 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
578 struct wbint_CheckMachineAccount
*r
)
580 struct winbindd_domain
*domain
;
584 domain
= wb_child_domain();
585 if (domain
== NULL
) {
586 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
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
)) {
610 if (!NT_STATUS_IS_OK(status
)) {
611 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
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"));
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
)));
629 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
630 struct wbint_ChangeMachineAccount
*r
)
632 struct winbindd_domain
*domain
;
635 struct rpc_pipe_client
*netlogon_pipe
;
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
)) {
663 if (!NT_STATUS_IS_OK(status
)) {
664 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
668 tmp_ctx
= talloc_new(p
->mem_ctx
);
670 status
= trust_pw_find_change_and_store_it(netlogon_pipe
,
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"));
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
)));
689 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
692 struct winbindd_domain
*domain
;
693 struct rpc_pipe_client
*netlogon_pipe
;
694 union netr_CONTROL_QUERY_INFORMATION info
;
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"));
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
,
730 reset_cm_connection_on_error(domain
, status
);
731 if (!NT_STATUS_IS_OK(status
)) {
732 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
737 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
738 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
739 "WERR_NOT_SUPPORTED\n",
741 return werror_to_ntstatus(werr
);
744 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));