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
);
583 domain
->conn
.netlogon_force_reauth
= true;
586 struct rpc_pipe_client
*netlogon_pipe
;
587 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
590 /* There is a race condition between fetching the trust account
591 password and the periodic machine password change. So it's
592 possible that the trust account password has been changed on us.
593 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
595 #define MAX_RETRIES 3
597 if ((num_retries
< MAX_RETRIES
)
598 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
603 if (!NT_STATUS_IS_OK(status
)) {
604 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
608 /* Pass back result code - zero for success, other values for
609 specific failures. */
611 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
612 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
615 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
616 ("Checking the trust account password for domain %s returned %s\n",
617 domain
->name
, nt_errstr(status
)));
622 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
623 struct wbint_ChangeMachineAccount
*r
)
625 struct messaging_context
*msg_ctx
= winbind_messaging_context();
626 struct winbindd_domain
*domain
;
628 struct rpc_pipe_client
*netlogon_pipe
;
630 domain
= wb_child_domain();
631 if (domain
== NULL
) {
632 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
635 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
636 if (!NT_STATUS_IS_OK(status
)) {
637 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
641 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
643 netlogon_pipe
->binding_handle
,
647 /* Pass back result code - zero for success, other values for
648 specific failures. */
650 DEBUG(3,("domain %s secret %s\n", domain
->name
,
651 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
654 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
655 ("Changing the trust account password for domain %s returned %s\n",
656 domain
->name
, nt_errstr(status
)));
661 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
664 struct winbindd_domain
*domain
;
665 struct rpc_pipe_client
*netlogon_pipe
;
666 union netr_CONTROL_QUERY_INFORMATION info
;
668 fstring logon_server
;
669 struct dcerpc_binding_handle
*b
;
671 domain
= wb_child_domain();
672 if (domain
== NULL
) {
673 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
676 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
677 reset_cm_connection_on_error(domain
, status
);
678 if (!NT_STATUS_IS_OK(status
)) {
679 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
684 b
= netlogon_pipe
->binding_handle
;
686 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
687 *r
->out
.dcname
= talloc_strdup(p
->mem_ctx
, domain
->dcname
);
688 if (*r
->out
.dcname
== NULL
) {
689 DEBUG(2, ("Could not allocate memory\n"));
690 return NT_STATUS_NO_MEMORY
;
694 * This provokes a WERR_NOT_SUPPORTED error message. This is
695 * documented in the wspp docs. I could not get a successful
696 * call to work, but the main point here is testing that the
697 * netlogon pipe works.
699 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
700 logon_server
, NETLOGON_CONTROL_QUERY
,
703 reset_cm_connection_on_error(domain
, status
);
704 if (!NT_STATUS_IS_OK(status
)) {
705 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
710 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
711 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
712 "WERR_NOT_SUPPORTED\n",
714 return werror_to_ntstatus(werr
);
717 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));