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 "librpc/gen_ndr/srv_wbint.h"
27 #include "../librpc/gen_ndr/cli_netlogon.h"
30 void _wbint_Ping(struct pipes_struct
*p
, struct wbint_Ping
*r
)
32 *r
->out
.out_data
= r
->in
.in_data
;
35 NTSTATUS
_wbint_LookupSid(struct pipes_struct
*p
, struct wbint_LookupSid
*r
)
37 struct winbindd_domain
*domain
= wb_child_domain();
40 enum lsa_SidType type
;
44 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
47 status
= domain
->methods
->sid_to_name(domain
, p
->mem_ctx
, r
->in
.sid
,
48 &dom_name
, &name
, &type
);
49 if (!NT_STATUS_IS_OK(status
)) {
53 *r
->out
.domain
= dom_name
;
59 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
61 struct winbindd_domain
*domain
= wb_child_domain();
64 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
67 return domain
->methods
->name_to_sid(
68 domain
, p
->mem_ctx
, r
->in
.domain
, r
->in
.name
, r
->in
.flags
,
69 r
->out
.sid
, r
->out
.type
);
72 NTSTATUS
_wbint_Sid2Uid(struct pipes_struct
*p
, struct wbint_Sid2Uid
*r
)
77 status
= idmap_sid_to_uid(r
->in
.dom_name
? r
->in
.dom_name
: "",
79 if (!NT_STATUS_IS_OK(status
)) {
86 NTSTATUS
_wbint_Sid2Gid(struct pipes_struct
*p
, struct wbint_Sid2Gid
*r
)
91 status
= idmap_sid_to_gid(r
->in
.dom_name
? r
->in
.dom_name
: "",
93 if (!NT_STATUS_IS_OK(status
)) {
100 NTSTATUS
_wbint_Uid2Sid(struct pipes_struct
*p
, struct wbint_Uid2Sid
*r
)
102 return idmap_uid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
103 r
->out
.sid
, r
->in
.uid
);
106 NTSTATUS
_wbint_Gid2Sid(struct pipes_struct
*p
, struct wbint_Gid2Sid
*r
)
108 return idmap_gid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
109 r
->out
.sid
, r
->in
.gid
);
112 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
117 status
= idmap_allocate_uid(&xid
);
118 if (!NT_STATUS_IS_OK(status
)) {
121 *r
->out
.uid
= xid
.id
;
125 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
130 status
= idmap_allocate_gid(&xid
);
131 if (!NT_STATUS_IS_OK(status
)) {
134 *r
->out
.gid
= xid
.id
;
138 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
140 struct winbindd_domain
*domain
= wb_child_domain();
142 if (domain
== NULL
) {
143 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
146 return domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
150 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
151 struct wbint_LookupUserAliases
*r
)
153 struct winbindd_domain
*domain
= wb_child_domain();
155 if (domain
== NULL
) {
156 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
159 return domain
->methods
->lookup_useraliases(
160 domain
, p
->mem_ctx
, r
->in
.sids
->num_sids
, r
->in
.sids
->sids
,
161 &r
->out
.rids
->num_rids
, &r
->out
.rids
->rids
);
164 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
165 struct wbint_LookupUserGroups
*r
)
167 struct winbindd_domain
*domain
= wb_child_domain();
169 if (domain
== NULL
) {
170 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
173 return domain
->methods
->lookup_usergroups(
174 domain
, p
->mem_ctx
, r
->in
.sid
,
175 &r
->out
.sids
->num_sids
, &r
->out
.sids
->sids
);
178 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
179 struct wbint_QuerySequenceNumber
*r
)
181 struct winbindd_domain
*domain
= wb_child_domain();
183 if (domain
== NULL
) {
184 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
187 return domain
->methods
->sequence_number(domain
, r
->out
.sequence
);
190 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
191 struct wbint_LookupGroupMembers
*r
)
193 struct winbindd_domain
*domain
= wb_child_domain();
194 uint32_t i
, num_names
;
195 struct dom_sid
*sid_mem
;
197 uint32_t *name_types
;
200 if (domain
== NULL
) {
201 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
204 status
= domain
->methods
->lookup_groupmem(
205 domain
, p
->mem_ctx
, r
->in
.sid
, r
->in
.type
,
206 &num_names
, &sid_mem
, &names
, &name_types
);
207 if (!NT_STATUS_IS_OK(status
)) {
211 r
->out
.members
->num_principals
= num_names
;
212 r
->out
.members
->principals
= talloc_array(
213 r
->out
.members
, struct wbint_Principal
, num_names
);
214 if (r
->out
.members
->principals
== NULL
) {
215 return NT_STATUS_NO_MEMORY
;
218 for (i
=0; i
<num_names
; i
++) {
219 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
220 sid_copy(&m
->sid
, &sid_mem
[i
]);
221 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
222 m
->type
= (enum lsa_SidType
)name_types
[i
];
228 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
229 struct wbint_QueryUserList
*r
)
231 struct winbindd_domain
*domain
= wb_child_domain();
233 if (domain
== NULL
) {
234 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
237 return domain
->methods
->query_user_list(
238 domain
, p
->mem_ctx
, &r
->out
.users
->num_userinfos
,
239 &r
->out
.users
->userinfos
);
242 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
243 struct wbint_QueryGroupList
*r
)
245 struct winbindd_domain
*domain
= wb_child_domain();
246 uint32_t i
, num_groups
;
247 struct acct_info
*groups
;
248 struct wbint_Principal
*result
;
251 if (domain
== NULL
) {
252 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
255 status
= domain
->methods
->enum_dom_groups(domain
, talloc_tos(),
256 &num_groups
, &groups
);
257 if (!NT_STATUS_IS_OK(status
)) {
261 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
263 if (result
== NULL
) {
264 return NT_STATUS_NO_MEMORY
;
267 for (i
=0; i
<num_groups
; i
++) {
268 sid_compose(&result
[i
].sid
, &domain
->sid
, groups
[i
].rid
);
269 result
[i
].type
= SID_NAME_DOM_GRP
;
270 result
[i
].name
= talloc_strdup(result
, groups
[i
].acct_name
);
271 if (result
[i
].name
== NULL
) {
274 return NT_STATUS_NO_MEMORY
;
278 r
->out
.groups
->num_principals
= num_groups
;
279 r
->out
.groups
->principals
= result
;
285 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
287 struct winbindd_domain
*domain
= wb_child_domain();
288 struct rpc_pipe_client
*netlogon_pipe
;
289 struct netr_DsRGetDCNameInfo
*dc_info
;
292 unsigned int orig_timeout
;
294 if (domain
== NULL
) {
295 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
296 r
->in
.domain_name
, r
->in
.domain_guid
,
297 r
->in
.site_name
? r
->in
.site_name
: "",
302 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
304 if (!NT_STATUS_IS_OK(status
)) {
305 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
309 /* This call can take a long time - allow the server to time out.
310 35 seconds should do it. */
312 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
314 if (domain
->active_directory
) {
315 status
= rpccli_netr_DsRGetDCName(
316 netlogon_pipe
, p
->mem_ctx
, domain
->dcname
,
317 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
318 r
->in
.flags
, r
->out
.dc_info
, &werr
);
319 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
325 * Fallback to less capable methods
328 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
329 if (dc_info
== NULL
) {
330 status
= NT_STATUS_NO_MEMORY
;
334 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
335 status
= rpccli_netr_GetDcName(
336 netlogon_pipe
, p
->mem_ctx
, domain
->dcname
,
337 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
339 status
= rpccli_netr_GetAnyDCName(
340 netlogon_pipe
, p
->mem_ctx
, domain
->dcname
,
341 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
344 if (!NT_STATUS_IS_OK(status
)) {
345 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
349 if (!W_ERROR_IS_OK(werr
)) {
350 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
352 status
= werror_to_ntstatus(werr
);
356 *r
->out
.dc_info
= dc_info
;
357 status
= NT_STATUS_OK
;
360 /* And restore our original timeout. */
361 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
366 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
368 struct winbindd_domain
*domain
= wb_child_domain();
371 enum lsa_SidType
*types
;
372 struct wbint_Principal
*result
;
376 if (domain
== NULL
) {
377 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
380 status
= domain
->methods
->rids_to_names(
381 domain
, talloc_tos(), &domain
->sid
, r
->in
.rids
->rids
,
382 r
->in
.rids
->num_rids
, &domain_name
, &names
, &types
);
383 if (!NT_STATUS_IS_OK(status
)) {
387 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
388 r
->in
.rids
->num_rids
);
389 if (result
== NULL
) {
390 return NT_STATUS_NO_MEMORY
;
393 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
394 sid_compose(&result
[i
].sid
, &domain
->sid
, r
->in
.rids
->rids
[i
]);
395 result
[i
].type
= types
[i
];
396 result
[i
].name
= talloc_move(result
, &names
[i
]);
401 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
402 r
->out
.names
->principals
= result
;
406 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
407 struct wbint_CheckMachineAccount
*r
)
409 struct winbindd_domain
*domain
;
413 domain
= wb_child_domain();
414 if (domain
== NULL
) {
415 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
419 invalidate_cm_connection(&domain
->conn
);
422 struct rpc_pipe_client
*netlogon_pipe
;
423 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
426 /* There is a race condition between fetching the trust account
427 password and the periodic machine password change. So it's
428 possible that the trust account password has been changed on us.
429 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
431 #define MAX_RETRIES 3
433 if ((num_retries
< MAX_RETRIES
)
434 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
439 if (!NT_STATUS_IS_OK(status
)) {
440 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
444 /* Pass back result code - zero for success, other values for
445 specific failures. */
447 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
448 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
451 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
452 ("Checking the trust account password for domain %s returned %s\n",
453 domain
->name
, nt_errstr(status
)));
458 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
459 struct wbint_ChangeMachineAccount
*r
)
461 struct winbindd_domain
*domain
;
464 struct rpc_pipe_client
*netlogon_pipe
;
468 domain
= wb_child_domain();
469 if (domain
== NULL
) {
470 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
473 invalidate_cm_connection(&domain
->conn
);
476 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
479 /* There is a race condition between fetching the trust account
480 password and the periodic machine password change. So it's
481 possible that the trust account password has been changed on us.
482 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
484 #define MAX_RETRIES 3
486 if ((num_retries
< MAX_RETRIES
)
487 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
492 if (!NT_STATUS_IS_OK(status
)) {
493 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
497 tmp_ctx
= talloc_new(p
->mem_ctx
);
499 status
= trust_pw_find_change_and_store_it(netlogon_pipe
,
502 talloc_destroy(tmp_ctx
);
504 /* Pass back result code - zero for success, other values for
505 specific failures. */
507 DEBUG(3,("domain %s secret %s\n", domain
->name
,
508 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
511 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
512 ("Changing the trust account password for domain %s returned %s\n",
513 domain
->name
, nt_errstr(status
)));
518 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
521 struct winbindd_domain
*domain
;
522 struct rpc_pipe_client
*netlogon_pipe
;
523 union netr_CONTROL_QUERY_INFORMATION info
;
525 fstring logon_server
;
527 domain
= wb_child_domain();
528 if (domain
== NULL
) {
529 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
532 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
533 if (!NT_STATUS_IS_OK(status
)) {
534 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
538 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
541 * This provokes a WERR_NOT_SUPPORTED error message. This is
542 * documented in the wspp docs. I could not get a successful
543 * call to work, but the main point here is testing that the
544 * netlogon pipe works.
546 status
= rpccli_netr_LogonControl(netlogon_pipe
, p
->mem_ctx
,
547 logon_server
, NETLOGON_CONTROL_QUERY
,
550 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
551 DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
552 invalidate_cm_connection(&domain
->conn
);
556 if (!NT_STATUS_EQUAL(status
, NT_STATUS_CTL_FILE_NOT_SUPPORTED
)) {
557 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
558 "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
563 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));