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"
29 void _wbint_Ping(struct pipes_struct
*p
, struct wbint_Ping
*r
)
31 *r
->out
.out_data
= r
->in
.in_data
;
34 NTSTATUS
_wbint_LookupSid(struct pipes_struct
*p
, struct wbint_LookupSid
*r
)
36 struct winbindd_domain
*domain
= wb_child_domain();
39 enum lsa_SidType type
;
43 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
46 status
= domain
->methods
->sid_to_name(domain
, p
->mem_ctx
, r
->in
.sid
,
47 &dom_name
, &name
, &type
);
48 if (!NT_STATUS_IS_OK(status
)) {
52 *r
->out
.domain
= dom_name
;
58 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
60 struct winbindd_domain
*domain
= wb_child_domain();
63 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
66 return domain
->methods
->name_to_sid(
67 domain
, p
->mem_ctx
, r
->in
.domain
, r
->in
.name
, r
->in
.flags
,
68 r
->out
.sid
, r
->out
.type
);
71 NTSTATUS
_wbint_Sid2Uid(struct pipes_struct
*p
, struct wbint_Sid2Uid
*r
)
76 status
= idmap_sid_to_uid(r
->in
.dom_name
? r
->in
.dom_name
: "",
78 if (!NT_STATUS_IS_OK(status
)) {
85 NTSTATUS
_wbint_Sid2Gid(struct pipes_struct
*p
, struct wbint_Sid2Gid
*r
)
90 status
= idmap_sid_to_gid(r
->in
.dom_name
? r
->in
.dom_name
: "",
92 if (!NT_STATUS_IS_OK(status
)) {
99 NTSTATUS
_wbint_Uid2Sid(struct pipes_struct
*p
, struct wbint_Uid2Sid
*r
)
101 return idmap_uid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
102 r
->out
.sid
, r
->in
.uid
);
105 NTSTATUS
_wbint_Gid2Sid(struct pipes_struct
*p
, struct wbint_Gid2Sid
*r
)
107 return idmap_gid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
108 r
->out
.sid
, r
->in
.gid
);
111 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
116 status
= idmap_allocate_uid(&xid
);
117 if (!NT_STATUS_IS_OK(status
)) {
120 *r
->out
.uid
= xid
.id
;
124 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
129 status
= idmap_allocate_gid(&xid
);
130 if (!NT_STATUS_IS_OK(status
)) {
133 *r
->out
.gid
= xid
.id
;
137 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
139 struct winbindd_domain
*domain
= wb_child_domain();
141 if (domain
== NULL
) {
142 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
145 return domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
149 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
150 struct wbint_LookupUserAliases
*r
)
152 struct winbindd_domain
*domain
= wb_child_domain();
154 if (domain
== NULL
) {
155 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
158 return domain
->methods
->lookup_useraliases(
159 domain
, p
->mem_ctx
, r
->in
.sids
->num_sids
, r
->in
.sids
->sids
,
160 &r
->out
.rids
->num_rids
, &r
->out
.rids
->rids
);
163 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
164 struct wbint_LookupUserGroups
*r
)
166 struct winbindd_domain
*domain
= wb_child_domain();
168 if (domain
== NULL
) {
169 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
172 return domain
->methods
->lookup_usergroups(
173 domain
, p
->mem_ctx
, r
->in
.sid
,
174 &r
->out
.sids
->num_sids
, &r
->out
.sids
->sids
);
177 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
178 struct wbint_QuerySequenceNumber
*r
)
180 struct winbindd_domain
*domain
= wb_child_domain();
182 if (domain
== NULL
) {
183 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
186 return domain
->methods
->sequence_number(domain
, r
->out
.sequence
);
189 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
190 struct wbint_LookupGroupMembers
*r
)
192 struct winbindd_domain
*domain
= wb_child_domain();
193 uint32_t i
, num_names
;
194 struct dom_sid
*sid_mem
;
196 uint32_t *name_types
;
199 if (domain
== NULL
) {
200 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
203 status
= domain
->methods
->lookup_groupmem(
204 domain
, p
->mem_ctx
, r
->in
.sid
, r
->in
.type
,
205 &num_names
, &sid_mem
, &names
, &name_types
);
206 if (!NT_STATUS_IS_OK(status
)) {
210 r
->out
.members
->num_principals
= num_names
;
211 r
->out
.members
->principals
= talloc_array(
212 r
->out
.members
, struct wbint_Principal
, num_names
);
213 if (r
->out
.members
->principals
== NULL
) {
214 return NT_STATUS_NO_MEMORY
;
217 for (i
=0; i
<num_names
; i
++) {
218 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
219 sid_copy(&m
->sid
, &sid_mem
[i
]);
220 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
221 m
->type
= (enum lsa_SidType
)name_types
[i
];
227 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
228 struct wbint_QueryUserList
*r
)
230 struct winbindd_domain
*domain
= wb_child_domain();
232 if (domain
== NULL
) {
233 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
236 return domain
->methods
->query_user_list(
237 domain
, p
->mem_ctx
, &r
->out
.users
->num_userinfos
,
238 &r
->out
.users
->userinfos
);
241 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
242 struct wbint_QueryGroupList
*r
)
244 struct winbindd_domain
*domain
= wb_child_domain();
245 uint32_t i
, num_groups
;
246 struct acct_info
*groups
;
247 struct wbint_Principal
*result
;
250 if (domain
== NULL
) {
251 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
254 status
= domain
->methods
->enum_dom_groups(domain
, talloc_tos(),
255 &num_groups
, &groups
);
256 if (!NT_STATUS_IS_OK(status
)) {
260 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
262 if (result
== NULL
) {
263 return NT_STATUS_NO_MEMORY
;
266 for (i
=0; i
<num_groups
; i
++) {
267 sid_compose(&result
[i
].sid
, &domain
->sid
, groups
[i
].rid
);
268 result
[i
].type
= SID_NAME_DOM_GRP
;
269 result
[i
].name
= talloc_strdup(result
, groups
[i
].acct_name
);
270 if (result
[i
].name
== NULL
) {
273 return NT_STATUS_NO_MEMORY
;
277 r
->out
.groups
->num_principals
= num_groups
;
278 r
->out
.groups
->principals
= result
;
284 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
286 struct winbindd_domain
*domain
= wb_child_domain();
287 struct rpc_pipe_client
*netlogon_pipe
;
288 struct netr_DsRGetDCNameInfo
*dc_info
;
291 unsigned int orig_timeout
;
293 if (domain
== NULL
) {
294 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
295 r
->in
.domain_name
, r
->in
.domain_guid
,
296 r
->in
.site_name
? r
->in
.site_name
: "",
301 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
303 if (!NT_STATUS_IS_OK(status
)) {
304 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
308 /* This call can take a long time - allow the server to time out.
309 35 seconds should do it. */
311 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
313 if (domain
->active_directory
) {
314 status
= rpccli_netr_DsRGetDCName(
315 netlogon_pipe
, p
->mem_ctx
, domain
->dcname
,
316 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
317 r
->in
.flags
, r
->out
.dc_info
, &werr
);
318 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
324 * Fallback to less capable methods
327 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
328 if (dc_info
== NULL
) {
329 status
= NT_STATUS_NO_MEMORY
;
333 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
334 status
= rpccli_netr_GetDcName(
335 netlogon_pipe
, p
->mem_ctx
, domain
->dcname
,
336 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
338 status
= rpccli_netr_GetAnyDCName(
339 netlogon_pipe
, p
->mem_ctx
, domain
->dcname
,
340 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
343 if (!NT_STATUS_IS_OK(status
)) {
344 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
348 if (!W_ERROR_IS_OK(werr
)) {
349 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
351 status
= werror_to_ntstatus(werr
);
355 *r
->out
.dc_info
= dc_info
;
356 status
= NT_STATUS_OK
;
359 /* And restore our original timeout. */
360 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
365 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
367 struct winbindd_domain
*domain
= wb_child_domain();
370 enum lsa_SidType
*types
;
371 struct wbint_Principal
*result
;
375 if (domain
== NULL
) {
376 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
379 status
= domain
->methods
->rids_to_names(
380 domain
, talloc_tos(), &domain
->sid
, r
->in
.rids
->rids
,
381 r
->in
.rids
->num_rids
, &domain_name
, &names
, &types
);
382 if (!NT_STATUS_IS_OK(status
)) {
386 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
387 r
->in
.rids
->num_rids
);
388 if (result
== NULL
) {
389 return NT_STATUS_NO_MEMORY
;
392 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
393 sid_compose(&result
[i
].sid
, &domain
->sid
, r
->in
.rids
->rids
[i
]);
394 result
[i
].type
= types
[i
];
395 result
[i
].name
= talloc_move(result
, &names
[i
]);
400 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
401 r
->out
.names
->principals
= result
;
405 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
406 struct wbint_CheckMachineAccount
*r
)
408 struct winbindd_domain
*domain
;
412 domain
= wb_child_domain();
413 if (domain
== NULL
) {
414 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
418 invalidate_cm_connection(&domain
->conn
);
421 struct rpc_pipe_client
*netlogon_pipe
;
422 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
425 /* There is a race condition between fetching the trust account
426 password and the periodic machine password change. So it's
427 possible that the trust account password has been changed on us.
428 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
430 #define MAX_RETRIES 3
432 if ((num_retries
< MAX_RETRIES
)
433 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
438 if (!NT_STATUS_IS_OK(status
)) {
439 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
443 /* Pass back result code - zero for success, other values for
444 specific failures. */
446 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
447 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
450 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
451 ("Checking the trust account password for domain %s returned %s\n",
452 domain
->name
, nt_errstr(status
)));
457 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
458 struct wbint_ChangeMachineAccount
*r
)
460 struct winbindd_domain
*domain
;
463 struct rpc_pipe_client
*netlogon_pipe
;
467 domain
= wb_child_domain();
468 if (domain
== NULL
) {
469 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
472 invalidate_cm_connection(&domain
->conn
);
475 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
478 /* There is a race condition between fetching the trust account
479 password and the periodic machine password change. So it's
480 possible that the trust account password has been changed on us.
481 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
483 #define MAX_RETRIES 3
485 if ((num_retries
< MAX_RETRIES
)
486 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
491 if (!NT_STATUS_IS_OK(status
)) {
492 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
496 tmp_ctx
= talloc_new(p
->mem_ctx
);
498 status
= trust_pw_find_change_and_store_it(netlogon_pipe
,
501 talloc_destroy(tmp_ctx
);
503 /* Pass back result code - zero for success, other values for
504 specific failures. */
506 DEBUG(3,("domain %s secret %s\n", domain
->name
,
507 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
510 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
511 ("Changing the trust account password for domain %s returned %s\n",
512 domain
->name
, nt_errstr(status
)));
517 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
520 struct winbindd_domain
*domain
;
521 struct rpc_pipe_client
*netlogon_pipe
;
522 union netr_CONTROL_QUERY_INFORMATION info
;
524 fstring logon_server
;
526 domain
= wb_child_domain();
527 if (domain
== NULL
) {
528 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
531 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
532 if (!NT_STATUS_IS_OK(status
)) {
533 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
537 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
540 * This provokes a WERR_NOT_SUPPORTED error message. This is
541 * documented in the wspp docs. I could not get a successful
542 * call to work, but the main point here is testing that the
543 * netlogon pipe works.
545 status
= rpccli_netr_LogonControl(netlogon_pipe
, p
->mem_ctx
,
546 logon_server
, NETLOGON_CONTROL_QUERY
,
549 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
550 DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
551 invalidate_cm_connection(&domain
->conn
);
555 if (!NT_STATUS_EQUAL(status
, NT_STATUS_CTL_FILE_NOT_SUPPORTED
)) {
556 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
557 "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
562 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
566 NTSTATUS
_wbint_SetMapping(struct pipes_struct
*p
, struct wbint_SetMapping
*r
)
571 map
.xid
.id
= r
->in
.id
;
572 map
.status
= ID_MAPPED
;
574 switch (r
->in
.type
) {
575 case WBINT_ID_TYPE_UID
:
576 map
.xid
.type
= ID_TYPE_UID
;
578 case WBINT_ID_TYPE_GID
:
579 map
.xid
.type
= ID_TYPE_GID
;
582 return NT_STATUS_INVALID_PARAMETER
;
585 return idmap_set_mapping(&map
);
588 NTSTATUS
_wbint_RemoveMapping(struct pipes_struct
*p
,
589 struct wbint_RemoveMapping
*r
)
594 map
.xid
.id
= r
->in
.id
;
595 map
.status
= ID_MAPPED
;
597 switch (r
->in
.type
) {
598 case WBINT_ID_TYPE_UID
:
599 map
.xid
.type
= ID_TYPE_UID
;
601 case WBINT_ID_TYPE_GID
:
602 map
.xid
.type
= ID_TYPE_GID
;
605 return NT_STATUS_INVALID_PARAMETER
;
608 return idmap_remove_mapping(&map
);
611 NTSTATUS
_wbint_SetHWM(struct pipes_struct
*p
, struct wbint_SetHWM
*r
)
618 switch (r
->in
.type
) {
619 case WBINT_ID_TYPE_UID
:
620 id
.type
= ID_TYPE_UID
;
621 status
= idmap_set_uid_hwm(&id
);
623 case WBINT_ID_TYPE_GID
:
624 id
.type
= ID_TYPE_GID
;
625 status
= idmap_set_gid_hwm(&id
);
628 status
= NT_STATUS_INVALID_PARAMETER
;