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"
32 #include "../libcli/auth/netlogon_creds_cli.h"
34 void _wbint_Ping(struct pipes_struct
*p
, struct wbint_Ping
*r
)
36 *r
->out
.out_data
= r
->in
.in_data
;
39 static bool reset_cm_connection_on_error(struct winbindd_domain
*domain
,
42 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
43 invalidate_cm_connection(&domain
->conn
);
44 /* We invalidated the connection. */
50 NTSTATUS
_wbint_LookupSid(struct pipes_struct
*p
, struct wbint_LookupSid
*r
)
52 struct winbindd_domain
*domain
= wb_child_domain();
55 enum lsa_SidType type
;
59 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
62 status
= domain
->methods
->sid_to_name(domain
, p
->mem_ctx
, r
->in
.sid
,
63 &dom_name
, &name
, &type
);
64 reset_cm_connection_on_error(domain
, status
);
65 if (!NT_STATUS_IS_OK(status
)) {
69 *r
->out
.domain
= dom_name
;
75 NTSTATUS
_wbint_LookupSids(struct pipes_struct
*p
, struct wbint_LookupSids
*r
)
77 struct winbindd_domain
*domain
= wb_child_domain();
78 struct lsa_RefDomainList
*domains
= r
->out
.domains
;
82 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
86 * This breaks the winbindd_domain->methods abstraction: This
87 * is only called for remote domains, and both winbindd_msrpc
88 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
89 * done at the wbint RPC layer.
91 status
= rpc_lookup_sids(p
->mem_ctx
, domain
, r
->in
.sids
,
92 &domains
, &r
->out
.names
);
94 if (domains
!= NULL
) {
95 r
->out
.domains
= domains
;
98 reset_cm_connection_on_error(domain
, status
);
102 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
104 struct winbindd_domain
*domain
= wb_child_domain();
107 if (domain
== NULL
) {
108 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
111 status
= domain
->methods
->name_to_sid(
112 domain
, p
->mem_ctx
, r
->in
.domain
, r
->in
.name
, r
->in
.flags
,
113 r
->out
.sid
, r
->out
.type
);
114 reset_cm_connection_on_error(domain
, status
);
118 NTSTATUS
_wbint_Sids2UnixIDs(struct pipes_struct
*p
,
119 struct wbint_Sids2UnixIDs
*r
)
122 struct id_map
*ids
= NULL
;
123 struct id_map
**id_ptrs
= NULL
;
124 struct dom_sid
*sids
= NULL
;
125 uint32_t *id_idx
= NULL
;
126 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
128 for (i
=0; i
<r
->in
.domains
->count
; i
++) {
129 struct lsa_DomainInfo
*d
= &r
->in
.domains
->domains
[i
];
130 struct idmap_domain
*dom
;
133 dom
= idmap_find_domain_with_sid(d
->name
.string
, d
->sid
);
135 DEBUG(10, ("idmap domain %s:%s not found\n",
136 d
->name
.string
, sid_string_dbg(d
->sid
)));
142 for (j
=0; j
<r
->in
.ids
->num_ids
; j
++) {
143 if (r
->in
.ids
->ids
[j
].domain_index
== i
) {
148 ids
= talloc_realloc(talloc_tos(), ids
,
149 struct id_map
, num_ids
);
153 id_ptrs
= talloc_realloc(talloc_tos(), id_ptrs
,
154 struct id_map
*, num_ids
+1);
155 if (id_ptrs
== NULL
) {
158 id_idx
= talloc_realloc(talloc_tos(), id_idx
,
160 if (id_idx
== NULL
) {
163 sids
= talloc_realloc(talloc_tos(), sids
,
164 struct dom_sid
, num_ids
);
172 * Convert the input data into a list of
173 * id_map structs suitable for handing in
174 * to the idmap sids_to_unixids method.
176 for (j
=0; j
<r
->in
.ids
->num_ids
; j
++) {
177 struct wbint_TransID
*id
= &r
->in
.ids
->ids
[j
];
179 if (id
->domain_index
!= i
) {
183 id_ptrs
[num_ids
] = &ids
[num_ids
];
185 ids
[num_ids
].sid
= &sids
[num_ids
];
186 sid_compose(ids
[num_ids
].sid
, d
->sid
, id
->rid
);
187 ids
[num_ids
].xid
.type
= id
->type
;
188 ids
[num_ids
].status
= ID_UNKNOWN
;
191 id_ptrs
[num_ids
] = NULL
;
193 status
= dom
->methods
->sids_to_unixids(dom
, id_ptrs
);
194 DEBUG(10, ("sids_to_unixids returned %s\n",
198 * Extract the results for handing them back to the caller.
200 for (j
=0; j
<num_ids
; j
++) {
201 struct wbint_TransID
*id
= &r
->in
.ids
->ids
[id_idx
[j
]];
203 if (ids
[j
].status
!= ID_MAPPED
) {
204 id
->xid
.id
= UINT32_MAX
;
205 id
->xid
.type
= ID_TYPE_NOT_SPECIFIED
;
209 id
->xid
= ids
[j
].xid
;
212 status
= NT_STATUS_OK
;
215 TALLOC_FREE(id_ptrs
);
221 NTSTATUS
_wbint_Uid2Sid(struct pipes_struct
*p
, struct wbint_Uid2Sid
*r
)
223 return idmap_uid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
224 r
->out
.sid
, r
->in
.uid
);
227 NTSTATUS
_wbint_Gid2Sid(struct pipes_struct
*p
, struct wbint_Gid2Sid
*r
)
229 return idmap_gid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
230 r
->out
.sid
, r
->in
.gid
);
233 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
238 status
= idmap_allocate_uid(&xid
);
239 if (!NT_STATUS_IS_OK(status
)) {
242 *r
->out
.uid
= xid
.id
;
246 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
251 status
= idmap_allocate_gid(&xid
);
252 if (!NT_STATUS_IS_OK(status
)) {
255 *r
->out
.gid
= xid
.id
;
259 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
261 struct winbindd_domain
*domain
= wb_child_domain();
264 if (domain
== NULL
) {
265 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
268 status
= domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
270 reset_cm_connection_on_error(domain
, status
);
274 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
275 struct wbint_LookupUserAliases
*r
)
277 struct winbindd_domain
*domain
= wb_child_domain();
280 if (domain
== NULL
) {
281 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
284 status
= domain
->methods
->lookup_useraliases(
285 domain
, p
->mem_ctx
, r
->in
.sids
->num_sids
, r
->in
.sids
->sids
,
286 &r
->out
.rids
->num_rids
, &r
->out
.rids
->rids
);
287 reset_cm_connection_on_error(domain
, status
);
291 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
292 struct wbint_LookupUserGroups
*r
)
294 struct winbindd_domain
*domain
= wb_child_domain();
297 if (domain
== NULL
) {
298 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
301 status
= domain
->methods
->lookup_usergroups(
302 domain
, p
->mem_ctx
, r
->in
.sid
,
303 &r
->out
.sids
->num_sids
, &r
->out
.sids
->sids
);
304 reset_cm_connection_on_error(domain
, status
);
308 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
309 struct wbint_QuerySequenceNumber
*r
)
311 struct winbindd_domain
*domain
= wb_child_domain();
314 if (domain
== NULL
) {
315 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
318 status
= domain
->methods
->sequence_number(domain
, r
->out
.sequence
);
319 reset_cm_connection_on_error(domain
, status
);
323 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
324 struct wbint_LookupGroupMembers
*r
)
326 struct winbindd_domain
*domain
= wb_child_domain();
327 uint32_t i
, num_names
;
328 struct dom_sid
*sid_mem
;
330 uint32_t *name_types
;
333 if (domain
== NULL
) {
334 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
337 status
= domain
->methods
->lookup_groupmem(
338 domain
, p
->mem_ctx
, r
->in
.sid
, r
->in
.type
,
339 &num_names
, &sid_mem
, &names
, &name_types
);
340 reset_cm_connection_on_error(domain
, status
);
341 if (!NT_STATUS_IS_OK(status
)) {
345 r
->out
.members
->num_principals
= num_names
;
346 r
->out
.members
->principals
= talloc_array(
347 r
->out
.members
, struct wbint_Principal
, num_names
);
348 if (r
->out
.members
->principals
== NULL
) {
349 return NT_STATUS_NO_MEMORY
;
352 for (i
=0; i
<num_names
; i
++) {
353 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
354 sid_copy(&m
->sid
, &sid_mem
[i
]);
355 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
356 m
->type
= (enum lsa_SidType
)name_types
[i
];
362 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
363 struct wbint_QueryUserList
*r
)
365 struct winbindd_domain
*domain
= wb_child_domain();
368 if (domain
== NULL
) {
369 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
372 status
= domain
->methods
->query_user_list(
373 domain
, p
->mem_ctx
, &r
->out
.users
->num_userinfos
,
374 &r
->out
.users
->userinfos
);
375 reset_cm_connection_on_error(domain
, status
);
379 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
380 struct wbint_QueryGroupList
*r
)
382 struct winbindd_domain
*domain
= wb_child_domain();
383 uint32_t i
, num_groups
;
384 struct wb_acct_info
*groups
;
385 struct wbint_Principal
*result
;
388 if (domain
== NULL
) {
389 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
392 status
= domain
->methods
->enum_dom_groups(domain
, talloc_tos(),
393 &num_groups
, &groups
);
394 reset_cm_connection_on_error(domain
, status
);
395 if (!NT_STATUS_IS_OK(status
)) {
399 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
401 if (result
== NULL
) {
402 return NT_STATUS_NO_MEMORY
;
405 for (i
=0; i
<num_groups
; i
++) {
406 sid_compose(&result
[i
].sid
, &domain
->sid
, groups
[i
].rid
);
407 result
[i
].type
= SID_NAME_DOM_GRP
;
408 result
[i
].name
= talloc_strdup(result
, groups
[i
].acct_name
);
409 if (result
[i
].name
== NULL
) {
412 return NT_STATUS_NO_MEMORY
;
416 r
->out
.groups
->num_principals
= num_groups
;
417 r
->out
.groups
->principals
= result
;
423 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
425 struct winbindd_domain
*domain
= wb_child_domain();
426 struct rpc_pipe_client
*netlogon_pipe
;
427 struct netr_DsRGetDCNameInfo
*dc_info
;
430 unsigned int orig_timeout
;
431 struct dcerpc_binding_handle
*b
;
433 if (domain
== NULL
) {
434 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
435 r
->in
.domain_name
, r
->in
.domain_guid
,
436 r
->in
.site_name
? r
->in
.site_name
: "",
441 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
443 reset_cm_connection_on_error(domain
, status
);
444 if (!NT_STATUS_IS_OK(status
)) {
445 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
449 b
= netlogon_pipe
->binding_handle
;
451 /* This call can take a long time - allow the server to time out.
452 35 seconds should do it. */
454 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
456 if (domain
->active_directory
) {
457 status
= dcerpc_netr_DsRGetDCName(b
,
458 p
->mem_ctx
, domain
->dcname
,
459 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
460 r
->in
.flags
, r
->out
.dc_info
, &werr
);
461 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
464 if (reset_cm_connection_on_error(domain
, status
)) {
466 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
468 reset_cm_connection_on_error(domain
, status
);
469 if (!NT_STATUS_IS_OK(status
)) {
470 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
474 b
= netlogon_pipe
->binding_handle
;
476 /* This call can take a long time - allow the server to time out.
477 35 seconds should do it. */
479 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
484 * Fallback to less capable methods
487 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
488 if (dc_info
== NULL
) {
489 status
= NT_STATUS_NO_MEMORY
;
493 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
494 status
= dcerpc_netr_GetDcName(b
,
495 p
->mem_ctx
, domain
->dcname
,
496 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
498 status
= dcerpc_netr_GetAnyDCName(b
,
499 p
->mem_ctx
, domain
->dcname
,
500 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
503 reset_cm_connection_on_error(domain
, status
);
504 if (!NT_STATUS_IS_OK(status
)) {
505 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
509 if (!W_ERROR_IS_OK(werr
)) {
510 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
512 status
= werror_to_ntstatus(werr
);
516 *r
->out
.dc_info
= dc_info
;
517 status
= NT_STATUS_OK
;
520 /* And restore our original timeout. */
521 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
526 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
528 struct winbindd_domain
*domain
= wb_child_domain();
531 enum lsa_SidType
*types
;
532 struct wbint_Principal
*result
;
536 if (domain
== NULL
) {
537 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
540 status
= domain
->methods
->rids_to_names(
541 domain
, talloc_tos(), r
->in
.domain_sid
, r
->in
.rids
->rids
,
542 r
->in
.rids
->num_rids
, &domain_name
, &names
, &types
);
543 reset_cm_connection_on_error(domain
, status
);
544 if (!NT_STATUS_IS_OK(status
)) {
548 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
550 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
551 r
->in
.rids
->num_rids
);
552 if (result
== NULL
) {
553 return NT_STATUS_NO_MEMORY
;
556 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
557 sid_compose(&result
[i
].sid
, r
->in
.domain_sid
,
558 r
->in
.rids
->rids
[i
]);
559 result
[i
].type
= types
[i
];
560 result
[i
].name
= talloc_move(result
, &names
[i
]);
565 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
566 r
->out
.names
->principals
= result
;
570 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
571 struct wbint_CheckMachineAccount
*r
)
573 struct winbindd_domain
*domain
;
577 domain
= wb_child_domain();
578 if (domain
== NULL
) {
579 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
583 invalidate_cm_connection(&domain
->conn
);
584 domain
->conn
.netlogon_force_reauth
= true;
587 struct rpc_pipe_client
*netlogon_pipe
;
588 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
591 /* There is a race condition between fetching the trust account
592 password and the periodic machine password change. So it's
593 possible that the trust account password has been changed on us.
594 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
596 #define MAX_RETRIES 3
598 if ((num_retries
< MAX_RETRIES
)
599 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
604 if (!NT_STATUS_IS_OK(status
)) {
605 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
609 /* Pass back result code - zero for success, other values for
610 specific failures. */
612 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
613 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
616 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
617 ("Checking the trust account password for domain %s returned %s\n",
618 domain
->name
, nt_errstr(status
)));
623 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
624 struct wbint_ChangeMachineAccount
*r
)
626 struct messaging_context
*msg_ctx
= winbind_messaging_context();
627 struct winbindd_domain
*domain
;
629 struct rpc_pipe_client
*netlogon_pipe
;
631 domain
= wb_child_domain();
632 if (domain
== NULL
) {
633 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
636 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
637 if (!NT_STATUS_IS_OK(status
)) {
638 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
642 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
644 netlogon_pipe
->binding_handle
,
648 /* Pass back result code - zero for success, other values for
649 specific failures. */
651 DEBUG(3,("domain %s secret %s\n", domain
->name
,
652 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
655 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
656 ("Changing the trust account password for domain %s returned %s\n",
657 domain
->name
, nt_errstr(status
)));
662 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
665 struct winbindd_domain
*domain
;
666 struct rpc_pipe_client
*netlogon_pipe
;
667 union netr_CONTROL_QUERY_INFORMATION info
;
669 fstring logon_server
;
670 struct dcerpc_binding_handle
*b
;
672 domain
= wb_child_domain();
673 if (domain
== NULL
) {
674 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
677 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
678 reset_cm_connection_on_error(domain
, status
);
679 if (!NT_STATUS_IS_OK(status
)) {
680 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
685 b
= netlogon_pipe
->binding_handle
;
687 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
688 *r
->out
.dcname
= talloc_strdup(p
->mem_ctx
, domain
->dcname
);
689 if (*r
->out
.dcname
== NULL
) {
690 DEBUG(2, ("Could not allocate memory\n"));
691 return NT_STATUS_NO_MEMORY
;
695 * This provokes a WERR_NOT_SUPPORTED error message. This is
696 * documented in the wspp docs. I could not get a successful
697 * call to work, but the main point here is testing that the
698 * netlogon pipe works.
700 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
701 logon_server
, NETLOGON_CONTROL_QUERY
,
704 reset_cm_connection_on_error(domain
, status
);
705 if (!NT_STATUS_IS_OK(status
)) {
706 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
711 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
712 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
713 "WERR_NOT_SUPPORTED\n",
715 return werror_to_ntstatus(werr
);
718 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
722 NTSTATUS
_wbint_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct
*p
,
723 struct wbint_DsrUpdateReadOnlyServerDnsRecords
*r
)
725 struct winbindd_domain
*domain
;
727 struct rpc_pipe_client
*netlogon_pipe
;
729 domain
= wb_child_domain();
730 if (domain
== NULL
) {
731 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
734 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
735 if (!NT_STATUS_IS_OK(status
)) {
736 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
740 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain
->conn
.netlogon_creds
,
741 netlogon_pipe
->binding_handle
,
746 /* Pass back result code - zero for success, other values for
747 specific failures. */
749 DEBUG(3,("DNS records for domain %s %s\n", domain
->name
,
750 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
753 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
754 ("Update of DNS records via RW DC %s returned %s\n",
755 domain
->name
, nt_errstr(status
)));