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(pipes_struct
*p
, struct wbint_Ping
*r
)
31 *r
->out
.out_data
= r
->in
.in_data
;
34 NTSTATUS
_wbint_LookupSid(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(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(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(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(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(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(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(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(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(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(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(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(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(pipes_struct
*p
, struct wbint_QueryUserList
*r
)
229 struct winbindd_domain
*domain
= wb_child_domain();
231 if (domain
== NULL
) {
232 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
235 return domain
->methods
->query_user_list(
236 domain
, p
->mem_ctx
, &r
->out
.users
->num_userinfos
,
237 &r
->out
.users
->userinfos
);
240 NTSTATUS
_wbint_QueryGroupList(pipes_struct
*p
, struct wbint_QueryGroupList
*r
)
242 struct winbindd_domain
*domain
= wb_child_domain();
243 uint32_t i
, num_groups
;
244 struct acct_info
*groups
;
245 struct wbint_Principal
*result
;
248 if (domain
== NULL
) {
249 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
252 status
= domain
->methods
->enum_dom_groups(domain
, talloc_tos(),
253 &num_groups
, &groups
);
254 if (!NT_STATUS_IS_OK(status
)) {
258 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
260 if (result
== NULL
) {
261 return NT_STATUS_NO_MEMORY
;
264 for (i
=0; i
<num_groups
; i
++) {
265 sid_compose(&result
[i
].sid
, &domain
->sid
, groups
[i
].rid
);
266 result
[i
].type
= SID_NAME_DOM_GRP
;
267 result
[i
].name
= talloc_strdup(result
, groups
[i
].acct_name
);
268 if (result
[i
].name
== NULL
) {
271 return NT_STATUS_NO_MEMORY
;
275 r
->out
.groups
->num_principals
= num_groups
;
276 r
->out
.groups
->principals
= result
;
280 NTSTATUS
_wbint_DsGetDcName(pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
282 struct winbindd_domain
*domain
= wb_child_domain();
283 struct rpc_pipe_client
*netlogon_pipe
;
284 struct netr_DsRGetDCNameInfo
*dc_info
;
287 unsigned int orig_timeout
;
289 if (domain
== NULL
) {
290 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
291 r
->in
.domain_name
, r
->in
.domain_guid
,
292 r
->in
.site_name
? r
->in
.site_name
: "",
297 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
299 if (!NT_STATUS_IS_OK(status
)) {
300 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
304 /* This call can take a long time - allow the server to time out.
305 35 seconds should do it. */
307 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
309 if (domain
->active_directory
) {
310 status
= rpccli_netr_DsRGetDCName(
311 netlogon_pipe
, p
->mem_ctx
, domain
->dcname
,
312 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
313 r
->in
.flags
, r
->out
.dc_info
, &werr
);
314 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
320 * Fallback to less capable methods
323 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
324 if (dc_info
== NULL
) {
325 status
= NT_STATUS_NO_MEMORY
;
329 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
330 status
= rpccli_netr_GetDcName(
331 netlogon_pipe
, p
->mem_ctx
, domain
->dcname
,
332 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
334 status
= rpccli_netr_GetAnyDCName(
335 netlogon_pipe
, p
->mem_ctx
, domain
->dcname
,
336 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
339 if (!NT_STATUS_IS_OK(status
)) {
340 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
344 if (!W_ERROR_IS_OK(werr
)) {
345 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
347 status
= werror_to_ntstatus(werr
);
351 *r
->out
.dc_info
= dc_info
;
352 status
= NT_STATUS_OK
;
355 /* And restore our original timeout. */
356 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
361 NTSTATUS
_wbint_LookupRids(pipes_struct
*p
, struct wbint_LookupRids
*r
)
363 struct winbindd_domain
*domain
= wb_child_domain();
366 enum lsa_SidType
*types
;
367 struct wbint_Principal
*result
;
371 if (domain
== NULL
) {
372 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
375 status
= domain
->methods
->rids_to_names(
376 domain
, talloc_tos(), &domain
->sid
, r
->in
.rids
->rids
,
377 r
->in
.rids
->num_rids
, &domain_name
, &names
, &types
);
378 if (!NT_STATUS_IS_OK(status
)) {
382 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
383 r
->in
.rids
->num_rids
);
384 if (result
== NULL
) {
385 return NT_STATUS_NO_MEMORY
;
388 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
389 sid_compose(&result
[i
].sid
, &domain
->sid
, r
->in
.rids
->rids
[i
]);
390 result
[i
].type
= types
[i
];
391 result
[i
].name
= talloc_move(result
, &names
[i
]);
396 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
397 r
->out
.names
->principals
= result
;
401 NTSTATUS
_wbint_CheckMachineAccount(pipes_struct
*p
,
402 struct wbint_CheckMachineAccount
*r
)
404 struct winbindd_domain
*domain
;
408 domain
= wb_child_domain();
409 if (domain
== NULL
) {
410 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
414 invalidate_cm_connection(&domain
->conn
);
417 struct rpc_pipe_client
*netlogon_pipe
;
418 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
421 /* There is a race condition between fetching the trust account
422 password and the periodic machine password change. So it's
423 possible that the trust account password has been changed on us.
424 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
426 #define MAX_RETRIES 3
428 if ((num_retries
< MAX_RETRIES
)
429 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
434 if (!NT_STATUS_IS_OK(status
)) {
435 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
439 /* Pass back result code - zero for success, other values for
440 specific failures. */
442 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
443 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
446 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
447 ("Checking the trust account password for domain %s returned %s\n",
448 domain
->name
, nt_errstr(status
)));
453 NTSTATUS
_wbint_ChangeMachineAccount(pipes_struct
*p
,
454 struct wbint_ChangeMachineAccount
*r
)
456 struct winbindd_domain
*domain
;
459 struct rpc_pipe_client
*netlogon_pipe
;
463 domain
= wb_child_domain();
464 if (domain
== NULL
) {
465 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
468 invalidate_cm_connection(&domain
->conn
);
471 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
474 /* There is a race condition between fetching the trust account
475 password and the periodic machine password change. So it's
476 possible that the trust account password has been changed on us.
477 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
479 #define MAX_RETRIES 3
481 if ((num_retries
< MAX_RETRIES
)
482 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
487 if (!NT_STATUS_IS_OK(status
)) {
488 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
492 tmp_ctx
= talloc_new(p
->mem_ctx
);
494 status
= trust_pw_find_change_and_store_it(netlogon_pipe
,
497 talloc_destroy(tmp_ctx
);
499 /* Pass back result code - zero for success, other values for
500 specific failures. */
502 DEBUG(3,("domain %s secret %s\n", domain
->name
,
503 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
506 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
507 ("Changing the trust account password for domain %s returned %s\n",
508 domain
->name
, nt_errstr(status
)));
513 NTSTATUS
_wbint_PingDc(pipes_struct
*p
, struct wbint_PingDc
*r
)
516 struct winbindd_domain
*domain
;
517 struct rpc_pipe_client
*netlogon_pipe
;
518 union netr_CONTROL_QUERY_INFORMATION info
;
520 fstring logon_server
;
522 domain
= wb_child_domain();
523 if (domain
== NULL
) {
524 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
527 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
528 if (!NT_STATUS_IS_OK(status
)) {
529 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
533 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
536 * This provokes a WERR_NOT_SUPPORTED error message. This is
537 * documented in the wspp docs. I could not get a successful
538 * call to work, but the main point here is testing that the
539 * netlogon pipe works.
541 status
= rpccli_netr_LogonControl(netlogon_pipe
, p
->mem_ctx
,
542 logon_server
, NETLOGON_CONTROL_QUERY
,
545 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
546 DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
547 invalidate_cm_connection(&domain
->conn
);
551 if (!NT_STATUS_EQUAL(status
, NT_STATUS_CTL_FILE_NOT_SUPPORTED
)) {
552 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
553 "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
558 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
562 NTSTATUS
_wbint_SetMapping(pipes_struct
*p
, struct wbint_SetMapping
*r
)
567 map
.xid
.id
= r
->in
.id
;
568 map
.status
= ID_MAPPED
;
570 switch (r
->in
.type
) {
571 case WBINT_ID_TYPE_UID
:
572 map
.xid
.type
= ID_TYPE_UID
;
574 case WBINT_ID_TYPE_GID
:
575 map
.xid
.type
= ID_TYPE_GID
;
578 return NT_STATUS_INVALID_PARAMETER
;
581 return idmap_set_mapping(&map
);
584 NTSTATUS
_wbint_RemoveMapping(pipes_struct
*p
, struct wbint_RemoveMapping
*r
)
589 map
.xid
.id
= r
->in
.id
;
590 map
.status
= ID_MAPPED
;
592 switch (r
->in
.type
) {
593 case WBINT_ID_TYPE_UID
:
594 map
.xid
.type
= ID_TYPE_UID
;
596 case WBINT_ID_TYPE_GID
:
597 map
.xid
.type
= ID_TYPE_GID
;
600 return NT_STATUS_INVALID_PARAMETER
;
603 return idmap_remove_mapping(&map
);
606 NTSTATUS
_wbint_SetHWM(pipes_struct
*p
, struct wbint_SetHWM
*r
)
614 case WBINT_ID_TYPE_UID
:
615 id
.type
= ID_TYPE_UID
;
616 status
= idmap_set_uid_hwm(&id
);
619 id
.type
= ID_TYPE_GID
;
620 status
= idmap_set_gid_hwm(&id
);
623 status
= NT_STATUS_INVALID_PARAMETER
;