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"
33 void _wbint_Ping(struct pipes_struct
*p
, struct wbint_Ping
*r
)
35 *r
->out
.out_data
= r
->in
.in_data
;
38 NTSTATUS
_wbint_LookupSid(struct pipes_struct
*p
, struct wbint_LookupSid
*r
)
40 struct winbindd_domain
*domain
= wb_child_domain();
43 enum lsa_SidType type
;
47 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
50 status
= domain
->methods
->sid_to_name(domain
, p
->mem_ctx
, r
->in
.sid
,
51 &dom_name
, &name
, &type
);
52 if (!NT_STATUS_IS_OK(status
)) {
56 *r
->out
.domain
= dom_name
;
62 NTSTATUS
_wbint_LookupSids(struct pipes_struct
*p
, struct wbint_LookupSids
*r
)
64 struct winbindd_domain
*domain
= wb_child_domain();
67 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
71 * This breaks the winbindd_domain->methods abstraction: This
72 * is only called for remote domains, and both winbindd_msrpc
73 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
74 * done at the wbint RPC layer.
76 return rpc_lookup_sids(p
->mem_ctx
, domain
, r
->in
.sids
,
77 &r
->out
.domains
, &r
->out
.names
);
80 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
82 struct winbindd_domain
*domain
= wb_child_domain();
85 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
88 return domain
->methods
->name_to_sid(
89 domain
, p
->mem_ctx
, r
->in
.domain
, r
->in
.name
, r
->in
.flags
,
90 r
->out
.sid
, r
->out
.type
);
93 NTSTATUS
_wbint_Sid2Uid(struct pipes_struct
*p
, struct wbint_Sid2Uid
*r
)
98 status
= idmap_sid_to_uid(r
->in
.dom_name
? r
->in
.dom_name
: "",
100 if (!NT_STATUS_IS_OK(status
)) {
107 NTSTATUS
_wbint_Sid2Gid(struct pipes_struct
*p
, struct wbint_Sid2Gid
*r
)
112 status
= idmap_sid_to_gid(r
->in
.dom_name
? r
->in
.dom_name
: "",
114 if (!NT_STATUS_IS_OK(status
)) {
121 NTSTATUS
_wbint_Sids2UnixIDs(struct pipes_struct
*p
,
122 struct wbint_Sids2UnixIDs
*r
)
125 struct id_map
*ids
= NULL
;
126 struct id_map
**id_ptrs
= NULL
;
127 struct dom_sid
*sids
= NULL
;
128 uint32_t *id_idx
= NULL
;
129 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
131 for (i
=0; i
<r
->in
.domains
->count
; i
++) {
132 struct lsa_DomainInfo
*d
= &r
->in
.domains
->domains
[i
];
133 struct idmap_domain
*dom
;
136 dom
= idmap_find_domain(d
->name
.string
);
138 DEBUG(10, ("idmap domain %s not found\n",
145 for (j
=0; j
<r
->in
.ids
->num_ids
; j
++) {
146 if (r
->in
.ids
->ids
[j
].domain_index
== i
) {
151 ids
= TALLOC_REALLOC_ARRAY(talloc_tos(), ids
,
152 struct id_map
, num_ids
);
156 id_ptrs
= TALLOC_REALLOC_ARRAY(talloc_tos(), id_ptrs
,
157 struct id_map
*, num_ids
+1);
158 if (id_ptrs
== NULL
) {
161 id_idx
= TALLOC_REALLOC_ARRAY(talloc_tos(), id_idx
,
163 if (id_idx
== NULL
) {
166 sids
= TALLOC_REALLOC_ARRAY(talloc_tos(), sids
,
167 struct dom_sid
, num_ids
);
174 for (j
=0; j
<r
->in
.ids
->num_ids
; j
++) {
175 struct wbint_TransID
*id
= &r
->in
.ids
->ids
[j
];
177 if (id
->domain_index
!= i
) {
181 id_ptrs
[num_ids
] = &ids
[num_ids
];
183 ids
[num_ids
].sid
= &sids
[num_ids
];
184 sid_compose(ids
[num_ids
].sid
, d
->sid
, id
->rid
);
185 ids
[num_ids
].xid
.type
= id
->type
;
186 ids
[num_ids
].status
= ID_UNKNOWN
;
189 id_ptrs
[num_ids
] = NULL
;
191 status
= dom
->methods
->sids_to_unixids(dom
, id_ptrs
);
192 DEBUG(10, ("sids_to_unixids returned %s\n",
195 for (j
=0; j
<num_ids
; j
++) {
196 struct wbint_TransID
*id
= &r
->in
.ids
->ids
[id_idx
[j
]];
198 if (ids
[j
].status
!= ID_MAPPED
) {
201 id
->unix_id
= ids
[j
].xid
.id
;
204 status
= NT_STATUS_OK
;
207 TALLOC_FREE(id_ptrs
);
213 NTSTATUS
_wbint_Uid2Sid(struct pipes_struct
*p
, struct wbint_Uid2Sid
*r
)
215 return idmap_uid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
216 r
->out
.sid
, r
->in
.uid
);
219 NTSTATUS
_wbint_Gid2Sid(struct pipes_struct
*p
, struct wbint_Gid2Sid
*r
)
221 return idmap_gid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
222 r
->out
.sid
, r
->in
.gid
);
225 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
230 status
= idmap_allocate_uid(&xid
);
231 if (!NT_STATUS_IS_OK(status
)) {
234 *r
->out
.uid
= xid
.id
;
238 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
243 status
= idmap_allocate_gid(&xid
);
244 if (!NT_STATUS_IS_OK(status
)) {
247 *r
->out
.gid
= xid
.id
;
251 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
253 struct winbindd_domain
*domain
= wb_child_domain();
255 if (domain
== NULL
) {
256 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
259 return domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
263 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
264 struct wbint_LookupUserAliases
*r
)
266 struct winbindd_domain
*domain
= wb_child_domain();
268 if (domain
== NULL
) {
269 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
272 return domain
->methods
->lookup_useraliases(
273 domain
, p
->mem_ctx
, r
->in
.sids
->num_sids
, r
->in
.sids
->sids
,
274 &r
->out
.rids
->num_rids
, &r
->out
.rids
->rids
);
277 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
278 struct wbint_LookupUserGroups
*r
)
280 struct winbindd_domain
*domain
= wb_child_domain();
282 if (domain
== NULL
) {
283 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
286 return domain
->methods
->lookup_usergroups(
287 domain
, p
->mem_ctx
, r
->in
.sid
,
288 &r
->out
.sids
->num_sids
, &r
->out
.sids
->sids
);
291 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
292 struct wbint_QuerySequenceNumber
*r
)
294 struct winbindd_domain
*domain
= wb_child_domain();
296 if (domain
== NULL
) {
297 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
300 return domain
->methods
->sequence_number(domain
, r
->out
.sequence
);
303 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
304 struct wbint_LookupGroupMembers
*r
)
306 struct winbindd_domain
*domain
= wb_child_domain();
307 uint32_t i
, num_names
;
308 struct dom_sid
*sid_mem
;
310 uint32_t *name_types
;
313 if (domain
== NULL
) {
314 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
317 status
= domain
->methods
->lookup_groupmem(
318 domain
, p
->mem_ctx
, r
->in
.sid
, r
->in
.type
,
319 &num_names
, &sid_mem
, &names
, &name_types
);
320 if (!NT_STATUS_IS_OK(status
)) {
324 r
->out
.members
->num_principals
= num_names
;
325 r
->out
.members
->principals
= talloc_array(
326 r
->out
.members
, struct wbint_Principal
, num_names
);
327 if (r
->out
.members
->principals
== NULL
) {
328 return NT_STATUS_NO_MEMORY
;
331 for (i
=0; i
<num_names
; i
++) {
332 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
333 sid_copy(&m
->sid
, &sid_mem
[i
]);
334 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
335 m
->type
= (enum lsa_SidType
)name_types
[i
];
341 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
342 struct wbint_QueryUserList
*r
)
344 struct winbindd_domain
*domain
= wb_child_domain();
346 if (domain
== NULL
) {
347 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
350 return domain
->methods
->query_user_list(
351 domain
, p
->mem_ctx
, &r
->out
.users
->num_userinfos
,
352 &r
->out
.users
->userinfos
);
355 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
356 struct wbint_QueryGroupList
*r
)
358 struct winbindd_domain
*domain
= wb_child_domain();
359 uint32_t i
, num_groups
;
360 struct wb_acct_info
*groups
;
361 struct wbint_Principal
*result
;
364 if (domain
== NULL
) {
365 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
368 status
= domain
->methods
->enum_dom_groups(domain
, talloc_tos(),
369 &num_groups
, &groups
);
370 if (!NT_STATUS_IS_OK(status
)) {
374 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
376 if (result
== NULL
) {
377 return NT_STATUS_NO_MEMORY
;
380 for (i
=0; i
<num_groups
; i
++) {
381 sid_compose(&result
[i
].sid
, &domain
->sid
, groups
[i
].rid
);
382 result
[i
].type
= SID_NAME_DOM_GRP
;
383 result
[i
].name
= talloc_strdup(result
, groups
[i
].acct_name
);
384 if (result
[i
].name
== NULL
) {
387 return NT_STATUS_NO_MEMORY
;
391 r
->out
.groups
->num_principals
= num_groups
;
392 r
->out
.groups
->principals
= result
;
398 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
400 struct winbindd_domain
*domain
= wb_child_domain();
401 struct rpc_pipe_client
*netlogon_pipe
;
402 struct netr_DsRGetDCNameInfo
*dc_info
;
405 unsigned int orig_timeout
;
406 struct dcerpc_binding_handle
*b
;
408 if (domain
== NULL
) {
409 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
410 r
->in
.domain_name
, r
->in
.domain_guid
,
411 r
->in
.site_name
? r
->in
.site_name
: "",
416 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
418 if (!NT_STATUS_IS_OK(status
)) {
419 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
423 b
= netlogon_pipe
->binding_handle
;
425 /* This call can take a long time - allow the server to time out.
426 35 seconds should do it. */
428 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
430 if (domain
->active_directory
) {
431 status
= dcerpc_netr_DsRGetDCName(b
,
432 p
->mem_ctx
, domain
->dcname
,
433 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
434 r
->in
.flags
, r
->out
.dc_info
, &werr
);
435 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
441 * Fallback to less capable methods
444 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
445 if (dc_info
== NULL
) {
446 status
= NT_STATUS_NO_MEMORY
;
450 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
451 status
= dcerpc_netr_GetDcName(b
,
452 p
->mem_ctx
, domain
->dcname
,
453 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
455 status
= dcerpc_netr_GetAnyDCName(b
,
456 p
->mem_ctx
, domain
->dcname
,
457 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
460 if (!NT_STATUS_IS_OK(status
)) {
461 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
465 if (!W_ERROR_IS_OK(werr
)) {
466 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
468 status
= werror_to_ntstatus(werr
);
472 *r
->out
.dc_info
= dc_info
;
473 status
= NT_STATUS_OK
;
476 /* And restore our original timeout. */
477 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
482 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
484 struct winbindd_domain
*domain
= wb_child_domain();
487 enum lsa_SidType
*types
;
488 struct wbint_Principal
*result
;
492 if (domain
== NULL
) {
493 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
496 status
= domain
->methods
->rids_to_names(
497 domain
, talloc_tos(), &domain
->sid
, r
->in
.rids
->rids
,
498 r
->in
.rids
->num_rids
, &domain_name
, &names
, &types
);
499 if (!NT_STATUS_IS_OK(status
)) {
503 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
505 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
506 r
->in
.rids
->num_rids
);
507 if (result
== NULL
) {
508 return NT_STATUS_NO_MEMORY
;
511 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
512 sid_compose(&result
[i
].sid
, &domain
->sid
, r
->in
.rids
->rids
[i
]);
513 result
[i
].type
= types
[i
];
514 result
[i
].name
= talloc_move(result
, &names
[i
]);
519 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
520 r
->out
.names
->principals
= result
;
524 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
525 struct wbint_CheckMachineAccount
*r
)
527 struct winbindd_domain
*domain
;
531 domain
= wb_child_domain();
532 if (domain
== NULL
) {
533 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
537 invalidate_cm_connection(&domain
->conn
);
540 struct rpc_pipe_client
*netlogon_pipe
;
541 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
544 /* There is a race condition between fetching the trust account
545 password and the periodic machine password change. So it's
546 possible that the trust account password has been changed on us.
547 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
549 #define MAX_RETRIES 3
551 if ((num_retries
< MAX_RETRIES
)
552 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
557 if (!NT_STATUS_IS_OK(status
)) {
558 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
562 /* Pass back result code - zero for success, other values for
563 specific failures. */
565 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
566 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
569 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
570 ("Checking the trust account password for domain %s returned %s\n",
571 domain
->name
, nt_errstr(status
)));
576 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
577 struct wbint_ChangeMachineAccount
*r
)
579 struct winbindd_domain
*domain
;
582 struct rpc_pipe_client
*netlogon_pipe
;
586 domain
= wb_child_domain();
587 if (domain
== NULL
) {
588 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
591 invalidate_cm_connection(&domain
->conn
);
594 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
597 /* There is a race condition between fetching the trust account
598 password and the periodic machine password change. So it's
599 possible that the trust account password has been changed on us.
600 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
602 #define MAX_RETRIES 3
604 if ((num_retries
< MAX_RETRIES
)
605 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
610 if (!NT_STATUS_IS_OK(status
)) {
611 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
615 tmp_ctx
= talloc_new(p
->mem_ctx
);
617 status
= trust_pw_find_change_and_store_it(netlogon_pipe
,
620 talloc_destroy(tmp_ctx
);
622 /* Pass back result code - zero for success, other values for
623 specific failures. */
625 DEBUG(3,("domain %s secret %s\n", domain
->name
,
626 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
629 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
630 ("Changing the trust account password for domain %s returned %s\n",
631 domain
->name
, nt_errstr(status
)));
636 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
639 struct winbindd_domain
*domain
;
640 struct rpc_pipe_client
*netlogon_pipe
;
641 union netr_CONTROL_QUERY_INFORMATION info
;
643 fstring logon_server
;
644 struct dcerpc_binding_handle
*b
;
646 domain
= wb_child_domain();
647 if (domain
== NULL
) {
648 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
651 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
652 if (!NT_STATUS_IS_OK(status
)) {
653 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
657 b
= netlogon_pipe
->binding_handle
;
659 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
662 * This provokes a WERR_NOT_SUPPORTED error message. This is
663 * documented in the wspp docs. I could not get a successful
664 * call to work, but the main point here is testing that the
665 * netlogon pipe works.
667 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
668 logon_server
, NETLOGON_CONTROL_QUERY
,
671 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
672 DEBUG(2, ("dcerpc_netr_LogonControl timed out\n"));
673 invalidate_cm_connection(&domain
->conn
);
677 if (!NT_STATUS_IS_OK(status
)) {
678 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
683 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
684 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
685 "WERR_NOT_SUPPORTED\n",
687 return werror_to_ntstatus(werr
);
690 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));