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();
77 struct lsa_RefDomainList
*domains
= r
->out
.domains
;
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
);
101 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
103 struct winbindd_domain
*domain
= wb_child_domain();
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
);
117 NTSTATUS
_wbint_Sids2UnixIDs(struct pipes_struct
*p
,
118 struct wbint_Sids2UnixIDs
*r
)
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
;
132 dom
= idmap_find_domain_with_sid(d
->name
.string
, d
->sid
);
134 DEBUG(10, ("idmap domain %s:%s not found\n",
135 d
->name
.string
, sid_string_dbg(d
->sid
)));
141 for (j
=0; j
<r
->in
.ids
->num_ids
; j
++) {
142 if (r
->in
.ids
->ids
[j
].domain_index
== i
) {
147 ids
= talloc_realloc(talloc_tos(), ids
,
148 struct id_map
, num_ids
);
152 id_ptrs
= talloc_realloc(talloc_tos(), id_ptrs
,
153 struct id_map
*, num_ids
+1);
154 if (id_ptrs
== NULL
) {
157 id_idx
= talloc_realloc(talloc_tos(), id_idx
,
159 if (id_idx
== NULL
) {
162 sids
= talloc_realloc(talloc_tos(), sids
,
163 struct dom_sid
, num_ids
);
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
) {
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
;
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",
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
;
208 id
->xid
= ids
[j
].xid
;
211 status
= NT_STATUS_OK
;
214 TALLOC_FREE(id_ptrs
);
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
)
237 status
= idmap_allocate_uid(&xid
);
238 if (!NT_STATUS_IS_OK(status
)) {
241 *r
->out
.uid
= xid
.id
;
245 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
250 status
= idmap_allocate_gid(&xid
);
251 if (!NT_STATUS_IS_OK(status
)) {
254 *r
->out
.gid
= xid
.id
;
258 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
260 struct winbindd_domain
*domain
= wb_child_domain();
263 if (domain
== NULL
) {
264 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
267 status
= domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
269 reset_cm_connection_on_error(domain
, status
);
273 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
274 struct wbint_LookupUserAliases
*r
)
276 struct winbindd_domain
*domain
= wb_child_domain();
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
);
290 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
291 struct wbint_LookupUserGroups
*r
)
293 struct winbindd_domain
*domain
= wb_child_domain();
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
);
307 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
308 struct wbint_QuerySequenceNumber
*r
)
310 struct winbindd_domain
*domain
= wb_child_domain();
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
);
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
;
329 uint32_t *name_types
;
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
)) {
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
];
361 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
362 struct wbint_QueryUserList
*r
)
364 struct winbindd_domain
*domain
= wb_child_domain();
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
);
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
;
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
)) {
398 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
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
) {
411 return NT_STATUS_NO_MEMORY
;
415 r
->out
.groups
->num_principals
= num_groups
;
416 r
->out
.groups
->principals
= result
;
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
;
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
: "",
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"));
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
)) {
463 if (reset_cm_connection_on_error(domain
, status
)) {
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"));
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
;
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
);
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",
508 if (!W_ERROR_IS_OK(werr
)) {
509 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
511 status
= werror_to_ntstatus(werr
);
515 *r
->out
.dc_info
= dc_info
;
516 status
= NT_STATUS_OK
;
519 /* And restore our original timeout. */
520 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
525 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
527 struct winbindd_domain
*domain
= wb_child_domain();
530 enum lsa_SidType
*types
;
531 struct wbint_Principal
*result
;
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
)) {
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
]);
564 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
565 r
->out
.names
->principals
= result
;
569 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
570 struct wbint_CheckMachineAccount
*r
)
572 struct winbindd_domain
*domain
;
576 domain
= wb_child_domain();
577 if (domain
== NULL
) {
578 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
582 invalidate_cm_connection(&domain
->conn
);
585 struct rpc_pipe_client
*netlogon_pipe
;
586 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
589 /* There is a race condition between fetching the trust account
590 password and the periodic machine password change. So it's
591 possible that the trust account password has been changed on us.
592 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
594 #define MAX_RETRIES 3
596 if ((num_retries
< MAX_RETRIES
)
597 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
602 if (!NT_STATUS_IS_OK(status
)) {
603 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
607 /* Pass back result code - zero for success, other values for
608 specific failures. */
610 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
611 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
614 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
615 ("Checking the trust account password for domain %s returned %s\n",
616 domain
->name
, nt_errstr(status
)));
621 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
622 struct wbint_ChangeMachineAccount
*r
)
624 struct winbindd_domain
*domain
;
627 struct rpc_pipe_client
*netlogon_pipe
;
631 domain
= wb_child_domain();
632 if (domain
== NULL
) {
633 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
636 invalidate_cm_connection(&domain
->conn
);
639 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
642 /* There is a race condition between fetching the trust account
643 password and the periodic machine password change. So it's
644 possible that the trust account password has been changed on us.
645 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
647 #define MAX_RETRIES 3
649 if ((num_retries
< MAX_RETRIES
)
650 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
655 if (!NT_STATUS_IS_OK(status
)) {
656 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
660 tmp_ctx
= talloc_new(p
->mem_ctx
);
662 status
= trust_pw_find_change_and_store_it(netlogon_pipe
,
665 talloc_destroy(tmp_ctx
);
667 /* Pass back result code - zero for success, other values for
668 specific failures. */
670 DEBUG(3,("domain %s secret %s\n", domain
->name
,
671 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
674 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
675 ("Changing the trust account password for domain %s returned %s\n",
676 domain
->name
, nt_errstr(status
)));
681 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
684 struct winbindd_domain
*domain
;
685 struct rpc_pipe_client
*netlogon_pipe
;
686 union netr_CONTROL_QUERY_INFORMATION info
;
688 fstring logon_server
;
689 struct dcerpc_binding_handle
*b
;
691 domain
= wb_child_domain();
692 if (domain
== NULL
) {
693 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
696 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
697 reset_cm_connection_on_error(domain
, status
);
698 if (!NT_STATUS_IS_OK(status
)) {
699 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
704 b
= netlogon_pipe
->binding_handle
;
706 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
707 *r
->out
.dcname
= talloc_strdup(p
->mem_ctx
, domain
->dcname
);
708 if (*r
->out
.dcname
== NULL
) {
709 DEBUG(2, ("Could not allocate memory\n"));
710 return NT_STATUS_NO_MEMORY
;
714 * This provokes a WERR_NOT_SUPPORTED error message. This is
715 * documented in the wspp docs. I could not get a successful
716 * call to work, but the main point here is testing that the
717 * netlogon pipe works.
719 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
720 logon_server
, NETLOGON_CONTROL_QUERY
,
723 reset_cm_connection_on_error(domain
, status
);
724 if (!NT_STATUS_IS_OK(status
)) {
725 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
730 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
731 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
732 "WERR_NOT_SUPPORTED\n",
734 return werror_to_ntstatus(werr
);
737 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));