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"
27 #include "librpc/gen_ndr/srv_wbint.h"
28 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../libcli/security/security.h"
32 void _wbint_Ping(struct pipes_struct
*p
, struct wbint_Ping
*r
)
34 *r
->out
.out_data
= r
->in
.in_data
;
37 NTSTATUS
_wbint_LookupSid(struct pipes_struct
*p
, struct wbint_LookupSid
*r
)
39 struct winbindd_domain
*domain
= wb_child_domain();
42 enum lsa_SidType type
;
46 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
49 status
= domain
->methods
->sid_to_name(domain
, p
->mem_ctx
, r
->in
.sid
,
50 &dom_name
, &name
, &type
);
51 if (!NT_STATUS_IS_OK(status
)) {
55 *r
->out
.domain
= dom_name
;
61 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
63 struct winbindd_domain
*domain
= wb_child_domain();
66 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
69 return domain
->methods
->name_to_sid(
70 domain
, p
->mem_ctx
, r
->in
.domain
, r
->in
.name
, r
->in
.flags
,
71 r
->out
.sid
, r
->out
.type
);
74 NTSTATUS
_wbint_Sid2Uid(struct pipes_struct
*p
, struct wbint_Sid2Uid
*r
)
79 status
= idmap_sid_to_uid(r
->in
.dom_name
? r
->in
.dom_name
: "",
81 if (!NT_STATUS_IS_OK(status
)) {
88 NTSTATUS
_wbint_Sid2Gid(struct pipes_struct
*p
, struct wbint_Sid2Gid
*r
)
93 status
= idmap_sid_to_gid(r
->in
.dom_name
? r
->in
.dom_name
: "",
95 if (!NT_STATUS_IS_OK(status
)) {
102 NTSTATUS
_wbint_Uid2Sid(struct pipes_struct
*p
, struct wbint_Uid2Sid
*r
)
104 return idmap_uid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
105 r
->out
.sid
, r
->in
.uid
);
108 NTSTATUS
_wbint_Gid2Sid(struct pipes_struct
*p
, struct wbint_Gid2Sid
*r
)
110 return idmap_gid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
111 r
->out
.sid
, r
->in
.gid
);
114 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
119 status
= idmap_allocate_uid(&xid
);
120 if (!NT_STATUS_IS_OK(status
)) {
123 *r
->out
.uid
= xid
.id
;
127 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
132 status
= idmap_allocate_gid(&xid
);
133 if (!NT_STATUS_IS_OK(status
)) {
136 *r
->out
.gid
= xid
.id
;
140 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
142 struct winbindd_domain
*domain
= wb_child_domain();
144 if (domain
== NULL
) {
145 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
148 return domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
152 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
153 struct wbint_LookupUserAliases
*r
)
155 struct winbindd_domain
*domain
= wb_child_domain();
157 if (domain
== NULL
) {
158 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
161 return domain
->methods
->lookup_useraliases(
162 domain
, p
->mem_ctx
, r
->in
.sids
->num_sids
, r
->in
.sids
->sids
,
163 &r
->out
.rids
->num_rids
, &r
->out
.rids
->rids
);
166 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
167 struct wbint_LookupUserGroups
*r
)
169 struct winbindd_domain
*domain
= wb_child_domain();
171 if (domain
== NULL
) {
172 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
175 return domain
->methods
->lookup_usergroups(
176 domain
, p
->mem_ctx
, r
->in
.sid
,
177 &r
->out
.sids
->num_sids
, &r
->out
.sids
->sids
);
180 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
181 struct wbint_QuerySequenceNumber
*r
)
183 struct winbindd_domain
*domain
= wb_child_domain();
185 if (domain
== NULL
) {
186 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
189 return domain
->methods
->sequence_number(domain
, r
->out
.sequence
);
192 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
193 struct wbint_LookupGroupMembers
*r
)
195 struct winbindd_domain
*domain
= wb_child_domain();
196 uint32_t i
, num_names
;
197 struct dom_sid
*sid_mem
;
199 uint32_t *name_types
;
202 if (domain
== NULL
) {
203 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
206 status
= domain
->methods
->lookup_groupmem(
207 domain
, p
->mem_ctx
, r
->in
.sid
, r
->in
.type
,
208 &num_names
, &sid_mem
, &names
, &name_types
);
209 if (!NT_STATUS_IS_OK(status
)) {
213 r
->out
.members
->num_principals
= num_names
;
214 r
->out
.members
->principals
= talloc_array(
215 r
->out
.members
, struct wbint_Principal
, num_names
);
216 if (r
->out
.members
->principals
== NULL
) {
217 return NT_STATUS_NO_MEMORY
;
220 for (i
=0; i
<num_names
; i
++) {
221 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
222 sid_copy(&m
->sid
, &sid_mem
[i
]);
223 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
224 m
->type
= (enum lsa_SidType
)name_types
[i
];
230 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
231 struct wbint_QueryUserList
*r
)
233 struct winbindd_domain
*domain
= wb_child_domain();
235 if (domain
== NULL
) {
236 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
239 return domain
->methods
->query_user_list(
240 domain
, p
->mem_ctx
, &r
->out
.users
->num_userinfos
,
241 &r
->out
.users
->userinfos
);
244 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
245 struct wbint_QueryGroupList
*r
)
247 struct winbindd_domain
*domain
= wb_child_domain();
248 uint32_t i
, num_groups
;
249 struct acct_info
*groups
;
250 struct wbint_Principal
*result
;
253 if (domain
== NULL
) {
254 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
257 status
= domain
->methods
->enum_dom_groups(domain
, talloc_tos(),
258 &num_groups
, &groups
);
259 if (!NT_STATUS_IS_OK(status
)) {
263 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
265 if (result
== NULL
) {
266 return NT_STATUS_NO_MEMORY
;
269 for (i
=0; i
<num_groups
; i
++) {
270 sid_compose(&result
[i
].sid
, &domain
->sid
, groups
[i
].rid
);
271 result
[i
].type
= SID_NAME_DOM_GRP
;
272 result
[i
].name
= talloc_strdup(result
, groups
[i
].acct_name
);
273 if (result
[i
].name
== NULL
) {
276 return NT_STATUS_NO_MEMORY
;
280 r
->out
.groups
->num_principals
= num_groups
;
281 r
->out
.groups
->principals
= result
;
287 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
289 struct winbindd_domain
*domain
= wb_child_domain();
290 struct rpc_pipe_client
*netlogon_pipe
;
291 struct netr_DsRGetDCNameInfo
*dc_info
;
294 unsigned int orig_timeout
;
295 struct dcerpc_binding_handle
*b
;
297 if (domain
== NULL
) {
298 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
299 r
->in
.domain_name
, r
->in
.domain_guid
,
300 r
->in
.site_name
? r
->in
.site_name
: "",
305 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
307 if (!NT_STATUS_IS_OK(status
)) {
308 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
312 b
= netlogon_pipe
->binding_handle
;
314 /* This call can take a long time - allow the server to time out.
315 35 seconds should do it. */
317 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
319 if (domain
->active_directory
) {
320 status
= dcerpc_netr_DsRGetDCName(b
,
321 p
->mem_ctx
, domain
->dcname
,
322 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
323 r
->in
.flags
, r
->out
.dc_info
, &werr
);
324 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
330 * Fallback to less capable methods
333 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
334 if (dc_info
== NULL
) {
335 status
= NT_STATUS_NO_MEMORY
;
339 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
340 status
= dcerpc_netr_GetDcName(b
,
341 p
->mem_ctx
, domain
->dcname
,
342 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
344 status
= dcerpc_netr_GetAnyDCName(b
,
345 p
->mem_ctx
, domain
->dcname
,
346 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
349 if (!NT_STATUS_IS_OK(status
)) {
350 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
354 if (!W_ERROR_IS_OK(werr
)) {
355 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
357 status
= werror_to_ntstatus(werr
);
361 *r
->out
.dc_info
= dc_info
;
362 status
= NT_STATUS_OK
;
365 /* And restore our original timeout. */
366 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
371 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
373 struct winbindd_domain
*domain
= wb_child_domain();
376 enum lsa_SidType
*types
;
377 struct wbint_Principal
*result
;
381 if (domain
== NULL
) {
382 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
385 status
= domain
->methods
->rids_to_names(
386 domain
, talloc_tos(), &domain
->sid
, r
->in
.rids
->rids
,
387 r
->in
.rids
->num_rids
, &domain_name
, &names
, &types
);
388 if (!NT_STATUS_IS_OK(status
)) {
392 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
394 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
395 r
->in
.rids
->num_rids
);
396 if (result
== NULL
) {
397 return NT_STATUS_NO_MEMORY
;
400 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
401 sid_compose(&result
[i
].sid
, &domain
->sid
, r
->in
.rids
->rids
[i
]);
402 result
[i
].type
= types
[i
];
403 result
[i
].name
= talloc_move(result
, &names
[i
]);
408 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
409 r
->out
.names
->principals
= result
;
413 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
414 struct wbint_CheckMachineAccount
*r
)
416 struct winbindd_domain
*domain
;
420 domain
= wb_child_domain();
421 if (domain
== NULL
) {
422 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
426 invalidate_cm_connection(&domain
->conn
);
429 struct rpc_pipe_client
*netlogon_pipe
;
430 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
433 /* There is a race condition between fetching the trust account
434 password and the periodic machine password change. So it's
435 possible that the trust account password has been changed on us.
436 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
438 #define MAX_RETRIES 3
440 if ((num_retries
< MAX_RETRIES
)
441 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
446 if (!NT_STATUS_IS_OK(status
)) {
447 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
451 /* Pass back result code - zero for success, other values for
452 specific failures. */
454 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
455 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
458 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
459 ("Checking the trust account password for domain %s returned %s\n",
460 domain
->name
, nt_errstr(status
)));
465 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
466 struct wbint_ChangeMachineAccount
*r
)
468 struct winbindd_domain
*domain
;
471 struct rpc_pipe_client
*netlogon_pipe
;
475 domain
= wb_child_domain();
476 if (domain
== NULL
) {
477 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
480 invalidate_cm_connection(&domain
->conn
);
483 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
486 /* There is a race condition between fetching the trust account
487 password and the periodic machine password change. So it's
488 possible that the trust account password has been changed on us.
489 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
491 #define MAX_RETRIES 3
493 if ((num_retries
< MAX_RETRIES
)
494 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
499 if (!NT_STATUS_IS_OK(status
)) {
500 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
504 tmp_ctx
= talloc_new(p
->mem_ctx
);
506 status
= trust_pw_find_change_and_store_it(netlogon_pipe
,
509 talloc_destroy(tmp_ctx
);
511 /* Pass back result code - zero for success, other values for
512 specific failures. */
514 DEBUG(3,("domain %s secret %s\n", domain
->name
,
515 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
518 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
519 ("Changing the trust account password for domain %s returned %s\n",
520 domain
->name
, nt_errstr(status
)));
525 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
528 struct winbindd_domain
*domain
;
529 struct rpc_pipe_client
*netlogon_pipe
;
530 union netr_CONTROL_QUERY_INFORMATION info
;
532 fstring logon_server
;
533 struct dcerpc_binding_handle
*b
;
535 domain
= wb_child_domain();
536 if (domain
== NULL
) {
537 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
540 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
541 if (!NT_STATUS_IS_OK(status
)) {
542 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
546 b
= netlogon_pipe
->binding_handle
;
548 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
551 * This provokes a WERR_NOT_SUPPORTED error message. This is
552 * documented in the wspp docs. I could not get a successful
553 * call to work, but the main point here is testing that the
554 * netlogon pipe works.
556 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
557 logon_server
, NETLOGON_CONTROL_QUERY
,
560 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
561 DEBUG(2, ("dcerpc_netr_LogonControl timed out\n"));
562 invalidate_cm_connection(&domain
->conn
);
566 if (!NT_STATUS_IS_OK(status
)) {
567 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
572 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
573 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
574 "WERR_NOT_SUPPORTED\n",
576 return werror_to_ntstatus(werr
);
579 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));