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_ARRAY(talloc_tos(), ids
,
170 struct id_map
, num_ids
);
174 id_ptrs
= TALLOC_REALLOC_ARRAY(talloc_tos(), id_ptrs
,
175 struct id_map
*, num_ids
+1);
176 if (id_ptrs
== NULL
) {
179 id_idx
= TALLOC_REALLOC_ARRAY(talloc_tos(), id_idx
,
181 if (id_idx
== NULL
) {
184 sids
= TALLOC_REALLOC_ARRAY(talloc_tos(), sids
,
185 struct dom_sid
, num_ids
);
192 for (j
=0; j
<r
->in
.ids
->num_ids
; j
++) {
193 struct wbint_TransID
*id
= &r
->in
.ids
->ids
[j
];
195 if (id
->domain_index
!= i
) {
199 id_ptrs
[num_ids
] = &ids
[num_ids
];
201 ids
[num_ids
].sid
= &sids
[num_ids
];
202 sid_compose(ids
[num_ids
].sid
, d
->sid
, id
->rid
);
203 ids
[num_ids
].xid
.type
= id
->type
;
204 ids
[num_ids
].status
= ID_UNKNOWN
;
207 id_ptrs
[num_ids
] = NULL
;
209 status
= dom
->methods
->sids_to_unixids(dom
, id_ptrs
);
210 DEBUG(10, ("sids_to_unixids returned %s\n",
213 for (j
=0; j
<num_ids
; j
++) {
214 struct wbint_TransID
*id
= &r
->in
.ids
->ids
[id_idx
[j
]];
216 if (ids
[j
].status
!= ID_MAPPED
) {
219 id
->unix_id
= ids
[j
].xid
.id
;
222 status
= NT_STATUS_OK
;
225 TALLOC_FREE(id_ptrs
);
231 NTSTATUS
_wbint_Uid2Sid(struct pipes_struct
*p
, struct wbint_Uid2Sid
*r
)
233 return idmap_uid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
234 r
->out
.sid
, r
->in
.uid
);
237 NTSTATUS
_wbint_Gid2Sid(struct pipes_struct
*p
, struct wbint_Gid2Sid
*r
)
239 return idmap_gid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
240 r
->out
.sid
, r
->in
.gid
);
243 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
248 status
= idmap_allocate_uid(&xid
);
249 if (!NT_STATUS_IS_OK(status
)) {
252 *r
->out
.uid
= xid
.id
;
256 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
261 status
= idmap_allocate_gid(&xid
);
262 if (!NT_STATUS_IS_OK(status
)) {
265 *r
->out
.gid
= xid
.id
;
269 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
271 struct winbindd_domain
*domain
= wb_child_domain();
274 if (domain
== NULL
) {
275 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
278 status
= domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
280 reset_cm_connection_on_error(domain
, status
);
284 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
285 struct wbint_LookupUserAliases
*r
)
287 struct winbindd_domain
*domain
= wb_child_domain();
290 if (domain
== NULL
) {
291 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
294 status
= domain
->methods
->lookup_useraliases(
295 domain
, p
->mem_ctx
, r
->in
.sids
->num_sids
, r
->in
.sids
->sids
,
296 &r
->out
.rids
->num_rids
, &r
->out
.rids
->rids
);
297 reset_cm_connection_on_error(domain
, status
);
301 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
302 struct wbint_LookupUserGroups
*r
)
304 struct winbindd_domain
*domain
= wb_child_domain();
307 if (domain
== NULL
) {
308 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
311 status
= domain
->methods
->lookup_usergroups(
312 domain
, p
->mem_ctx
, r
->in
.sid
,
313 &r
->out
.sids
->num_sids
, &r
->out
.sids
->sids
);
314 reset_cm_connection_on_error(domain
, status
);
318 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
319 struct wbint_QuerySequenceNumber
*r
)
321 struct winbindd_domain
*domain
= wb_child_domain();
324 if (domain
== NULL
) {
325 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
328 status
= domain
->methods
->sequence_number(domain
, r
->out
.sequence
);
329 reset_cm_connection_on_error(domain
, status
);
333 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
334 struct wbint_LookupGroupMembers
*r
)
336 struct winbindd_domain
*domain
= wb_child_domain();
337 uint32_t i
, num_names
;
338 struct dom_sid
*sid_mem
;
340 uint32_t *name_types
;
343 if (domain
== NULL
) {
344 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
347 status
= domain
->methods
->lookup_groupmem(
348 domain
, p
->mem_ctx
, r
->in
.sid
, r
->in
.type
,
349 &num_names
, &sid_mem
, &names
, &name_types
);
350 reset_cm_connection_on_error(domain
, status
);
351 if (!NT_STATUS_IS_OK(status
)) {
355 r
->out
.members
->num_principals
= num_names
;
356 r
->out
.members
->principals
= talloc_array(
357 r
->out
.members
, struct wbint_Principal
, num_names
);
358 if (r
->out
.members
->principals
== NULL
) {
359 return NT_STATUS_NO_MEMORY
;
362 for (i
=0; i
<num_names
; i
++) {
363 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
364 sid_copy(&m
->sid
, &sid_mem
[i
]);
365 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
366 m
->type
= (enum lsa_SidType
)name_types
[i
];
372 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
373 struct wbint_QueryUserList
*r
)
375 struct winbindd_domain
*domain
= wb_child_domain();
378 if (domain
== NULL
) {
379 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
382 status
= domain
->methods
->query_user_list(
383 domain
, p
->mem_ctx
, &r
->out
.users
->num_userinfos
,
384 &r
->out
.users
->userinfos
);
385 reset_cm_connection_on_error(domain
, status
);
389 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
390 struct wbint_QueryGroupList
*r
)
392 struct winbindd_domain
*domain
= wb_child_domain();
393 uint32_t i
, num_groups
;
394 struct wb_acct_info
*groups
;
395 struct wbint_Principal
*result
;
398 if (domain
== NULL
) {
399 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
402 status
= domain
->methods
->enum_dom_groups(domain
, talloc_tos(),
403 &num_groups
, &groups
);
404 reset_cm_connection_on_error(domain
, status
);
405 if (!NT_STATUS_IS_OK(status
)) {
409 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
411 if (result
== NULL
) {
412 return NT_STATUS_NO_MEMORY
;
415 for (i
=0; i
<num_groups
; i
++) {
416 sid_compose(&result
[i
].sid
, &domain
->sid
, groups
[i
].rid
);
417 result
[i
].type
= SID_NAME_DOM_GRP
;
418 result
[i
].name
= talloc_strdup(result
, groups
[i
].acct_name
);
419 if (result
[i
].name
== NULL
) {
422 return NT_STATUS_NO_MEMORY
;
426 r
->out
.groups
->num_principals
= num_groups
;
427 r
->out
.groups
->principals
= result
;
433 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
435 struct winbindd_domain
*domain
= wb_child_domain();
436 struct rpc_pipe_client
*netlogon_pipe
;
437 struct netr_DsRGetDCNameInfo
*dc_info
;
440 unsigned int orig_timeout
;
441 struct dcerpc_binding_handle
*b
;
443 if (domain
== NULL
) {
444 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
445 r
->in
.domain_name
, r
->in
.domain_guid
,
446 r
->in
.site_name
? r
->in
.site_name
: "",
451 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
453 reset_cm_connection_on_error(domain
, status
);
454 if (!NT_STATUS_IS_OK(status
)) {
455 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
459 b
= netlogon_pipe
->binding_handle
;
461 /* This call can take a long time - allow the server to time out.
462 35 seconds should do it. */
464 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
466 if (domain
->active_directory
) {
467 status
= dcerpc_netr_DsRGetDCName(b
,
468 p
->mem_ctx
, domain
->dcname
,
469 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
470 r
->in
.flags
, r
->out
.dc_info
, &werr
);
471 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
474 if (reset_cm_connection_on_error(domain
, status
)) {
476 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
478 reset_cm_connection_on_error(domain
, status
);
479 if (!NT_STATUS_IS_OK(status
)) {
480 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
484 b
= netlogon_pipe
->binding_handle
;
486 /* This call can take a long time - allow the server to time out.
487 35 seconds should do it. */
489 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
494 * Fallback to less capable methods
497 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
498 if (dc_info
== NULL
) {
499 status
= NT_STATUS_NO_MEMORY
;
503 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
504 status
= dcerpc_netr_GetDcName(b
,
505 p
->mem_ctx
, domain
->dcname
,
506 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
508 status
= dcerpc_netr_GetAnyDCName(b
,
509 p
->mem_ctx
, domain
->dcname
,
510 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
513 reset_cm_connection_on_error(domain
, status
);
514 if (!NT_STATUS_IS_OK(status
)) {
515 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
519 if (!W_ERROR_IS_OK(werr
)) {
520 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
522 status
= werror_to_ntstatus(werr
);
526 *r
->out
.dc_info
= dc_info
;
527 status
= NT_STATUS_OK
;
530 /* And restore our original timeout. */
531 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
536 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
538 struct winbindd_domain
*domain
= wb_child_domain();
541 enum lsa_SidType
*types
;
542 struct wbint_Principal
*result
;
546 if (domain
== NULL
) {
547 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
550 status
= domain
->methods
->rids_to_names(
551 domain
, talloc_tos(), &domain
->sid
, r
->in
.rids
->rids
,
552 r
->in
.rids
->num_rids
, &domain_name
, &names
, &types
);
553 reset_cm_connection_on_error(domain
, status
);
554 if (!NT_STATUS_IS_OK(status
)) {
558 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
560 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
561 r
->in
.rids
->num_rids
);
562 if (result
== NULL
) {
563 return NT_STATUS_NO_MEMORY
;
566 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
567 sid_compose(&result
[i
].sid
, &domain
->sid
, r
->in
.rids
->rids
[i
]);
568 result
[i
].type
= types
[i
];
569 result
[i
].name
= talloc_move(result
, &names
[i
]);
574 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
575 r
->out
.names
->principals
= result
;
579 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
580 struct wbint_CheckMachineAccount
*r
)
582 struct winbindd_domain
*domain
;
586 domain
= wb_child_domain();
587 if (domain
== NULL
) {
588 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
592 invalidate_cm_connection(&domain
->conn
);
595 struct rpc_pipe_client
*netlogon_pipe
;
596 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
599 /* There is a race condition between fetching the trust account
600 password and the periodic machine password change. So it's
601 possible that the trust account password has been changed on us.
602 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
604 #define MAX_RETRIES 3
606 if ((num_retries
< MAX_RETRIES
)
607 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
612 if (!NT_STATUS_IS_OK(status
)) {
613 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
617 /* Pass back result code - zero for success, other values for
618 specific failures. */
620 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
621 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
624 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
625 ("Checking the trust account password for domain %s returned %s\n",
626 domain
->name
, nt_errstr(status
)));
631 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
632 struct wbint_ChangeMachineAccount
*r
)
634 struct winbindd_domain
*domain
;
637 struct rpc_pipe_client
*netlogon_pipe
;
641 domain
= wb_child_domain();
642 if (domain
== NULL
) {
643 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
646 invalidate_cm_connection(&domain
->conn
);
649 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
652 /* There is a race condition between fetching the trust account
653 password and the periodic machine password change. So it's
654 possible that the trust account password has been changed on us.
655 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
657 #define MAX_RETRIES 3
659 if ((num_retries
< MAX_RETRIES
)
660 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
665 if (!NT_STATUS_IS_OK(status
)) {
666 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
670 tmp_ctx
= talloc_new(p
->mem_ctx
);
672 status
= trust_pw_find_change_and_store_it(netlogon_pipe
,
675 talloc_destroy(tmp_ctx
);
677 /* Pass back result code - zero for success, other values for
678 specific failures. */
680 DEBUG(3,("domain %s secret %s\n", domain
->name
,
681 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
684 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
685 ("Changing the trust account password for domain %s returned %s\n",
686 domain
->name
, nt_errstr(status
)));
691 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
694 struct winbindd_domain
*domain
;
695 struct rpc_pipe_client
*netlogon_pipe
;
696 union netr_CONTROL_QUERY_INFORMATION info
;
698 fstring logon_server
;
699 struct dcerpc_binding_handle
*b
;
701 domain
= wb_child_domain();
702 if (domain
== NULL
) {
703 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
706 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
707 reset_cm_connection_on_error(domain
, status
);
708 if (!NT_STATUS_IS_OK(status
)) {
709 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
713 b
= netlogon_pipe
->binding_handle
;
715 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
718 * This provokes a WERR_NOT_SUPPORTED error message. This is
719 * documented in the wspp docs. I could not get a successful
720 * call to work, but the main point here is testing that the
721 * netlogon pipe works.
723 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
724 logon_server
, NETLOGON_CONTROL_QUERY
,
727 reset_cm_connection_on_error(domain
, status
);
728 if (!NT_STATUS_IS_OK(status
)) {
729 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
734 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
735 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
736 "WERR_NOT_SUPPORTED\n",
738 return werror_to_ntstatus(werr
);
741 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));