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/ndr_netlogon_c.h"
29 #include "../libcli/security/security.h"
31 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
33 *r->out.out_data = r->in.in_data;
36 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
38 struct winbindd_domain *domain = wb_child_domain();
41 enum lsa_SidType type;
45 return NT_STATUS_REQUEST_NOT_ACCEPTED;
48 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
49 &dom_name, &name, &type);
50 if (!NT_STATUS_IS_OK(status)) {
54 *r->out.domain = dom_name;
60 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
62 struct winbindd_domain *domain = wb_child_domain();
65 return NT_STATUS_REQUEST_NOT_ACCEPTED;
68 return domain->methods->name_to_sid(
69 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
70 r->out.sid, r->out.type);
73 NTSTATUS _wbint_Sid2Uid(struct pipes_struct *p, struct wbint_Sid2Uid *r)
78 status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
80 if (!NT_STATUS_IS_OK(status)) {
87 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
92 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
94 if (!NT_STATUS_IS_OK(status)) {
101 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
103 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
104 r->out.sid, r->in.uid);
107 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
109 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
110 r->out.sid, r->in.gid);
113 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
118 status = idmap_allocate_uid(&xid);
119 if (!NT_STATUS_IS_OK(status)) {
122 *r->out.uid = xid.id;
126 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
131 status = idmap_allocate_gid(&xid);
132 if (!NT_STATUS_IS_OK(status)) {
135 *r->out.gid = xid.id;
139 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
141 struct winbindd_domain *domain = wb_child_domain();
143 if (domain == NULL) {
144 return NT_STATUS_REQUEST_NOT_ACCEPTED;
147 return domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
151 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
152 struct wbint_LookupUserAliases *r)
154 struct winbindd_domain *domain = wb_child_domain();
156 if (domain == NULL) {
157 return NT_STATUS_REQUEST_NOT_ACCEPTED;
160 return domain->methods->lookup_useraliases(
161 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
162 &r->out.rids->num_rids, &r->out.rids->rids);
165 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
166 struct wbint_LookupUserGroups *r)
168 struct winbindd_domain *domain = wb_child_domain();
170 if (domain == NULL) {
171 return NT_STATUS_REQUEST_NOT_ACCEPTED;
174 return domain->methods->lookup_usergroups(
175 domain, p->mem_ctx, r->in.sid,
176 &r->out.sids->num_sids, &r->out.sids->sids);
179 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
180 struct wbint_QuerySequenceNumber *r)
182 struct winbindd_domain *domain = wb_child_domain();
184 if (domain == NULL) {
185 return NT_STATUS_REQUEST_NOT_ACCEPTED;
188 return domain->methods->sequence_number(domain, r->out.sequence);
191 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
192 struct wbint_LookupGroupMembers *r)
194 struct winbindd_domain *domain = wb_child_domain();
195 uint32_t i, num_names;
196 struct dom_sid *sid_mem;
198 uint32_t *name_types;
201 if (domain == NULL) {
202 return NT_STATUS_REQUEST_NOT_ACCEPTED;
205 status = domain->methods->lookup_groupmem(
206 domain, p->mem_ctx, r->in.sid, r->in.type,
207 &num_names, &sid_mem, &names, &name_types);
208 if (!NT_STATUS_IS_OK(status)) {
212 r->out.members->num_principals = num_names;
213 r->out.members->principals = talloc_array(
214 r->out.members, struct wbint_Principal, num_names);
215 if (r->out.members->principals == NULL) {
216 return NT_STATUS_NO_MEMORY;
219 for (i=0; i<num_names; i++) {
220 struct wbint_Principal *m = &r->out.members->principals[i];
221 sid_copy(&m->sid, &sid_mem[i]);
222 m->name = talloc_move(r->out.members->principals, &names[i]);
223 m->type = (enum lsa_SidType)name_types[i];
229 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
230 struct wbint_QueryUserList *r)
232 struct winbindd_domain *domain = wb_child_domain();
234 if (domain == NULL) {
235 return NT_STATUS_REQUEST_NOT_ACCEPTED;
238 return domain->methods->query_user_list(
239 domain, p->mem_ctx, &r->out.users->num_userinfos,
240 &r->out.users->userinfos);
243 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
244 struct wbint_QueryGroupList *r)
246 struct winbindd_domain *domain = wb_child_domain();
247 uint32_t i, num_groups;
248 struct acct_info *groups;
249 struct wbint_Principal *result;
252 if (domain == NULL) {
253 return NT_STATUS_REQUEST_NOT_ACCEPTED;
256 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
257 &num_groups, &groups);
258 if (!NT_STATUS_IS_OK(status)) {
262 result = talloc_array(r->out.groups, struct wbint_Principal,
264 if (result == NULL) {
265 return NT_STATUS_NO_MEMORY;
268 for (i=0; i<num_groups; i++) {
269 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
270 result[i].type = SID_NAME_DOM_GRP;
271 result[i].name = talloc_strdup(result, groups[i].acct_name);
272 if (result[i].name == NULL) {
275 return NT_STATUS_NO_MEMORY;
279 r->out.groups->num_principals = num_groups;
280 r->out.groups->principals = result;
286 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
288 struct winbindd_domain *domain = wb_child_domain();
289 struct rpc_pipe_client *netlogon_pipe;
290 struct netr_DsRGetDCNameInfo *dc_info;
293 unsigned int orig_timeout;
294 struct dcerpc_binding_handle *b;
296 if (domain == NULL) {
297 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
298 r->in.domain_name, r->in.domain_guid,
299 r->in.site_name ? r->in.site_name : "",
304 status = cm_connect_netlogon(domain, &netlogon_pipe);
306 if (!NT_STATUS_IS_OK(status)) {
307 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
311 b = netlogon_pipe->binding_handle;
313 /* This call can take a long time - allow the server to time out.
314 35 seconds should do it. */
316 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
318 if (domain->active_directory) {
319 status = dcerpc_netr_DsRGetDCName(b,
320 p->mem_ctx, domain->dcname,
321 r->in.domain_name, NULL, r->in.domain_guid,
322 r->in.flags, r->out.dc_info, &werr);
323 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
329 * Fallback to less capable methods
332 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
333 if (dc_info == NULL) {
334 status = NT_STATUS_NO_MEMORY;
338 if (r->in.flags & DS_PDC_REQUIRED) {
339 status = dcerpc_netr_GetDcName(b,
340 p->mem_ctx, domain->dcname,
341 r->in.domain_name, &dc_info->dc_unc, &werr);
343 status = dcerpc_netr_GetAnyDCName(b,
344 p->mem_ctx, domain->dcname,
345 r->in.domain_name, &dc_info->dc_unc, &werr);
348 if (!NT_STATUS_IS_OK(status)) {
349 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
353 if (!W_ERROR_IS_OK(werr)) {
354 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
356 status = werror_to_ntstatus(werr);
360 *r->out.dc_info = dc_info;
361 status = NT_STATUS_OK;
364 /* And restore our original timeout. */
365 rpccli_set_timeout(netlogon_pipe, orig_timeout);
370 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
372 struct winbindd_domain *domain = wb_child_domain();
375 enum lsa_SidType *types;
376 struct wbint_Principal *result;
380 if (domain == NULL) {
381 return NT_STATUS_REQUEST_NOT_ACCEPTED;
384 status = domain->methods->rids_to_names(
385 domain, talloc_tos(), &domain->sid, r->in.rids->rids,
386 r->in.rids->num_rids, &domain_name, &names, &types);
387 if (!NT_STATUS_IS_OK(status)) {
391 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
393 result = talloc_array(p->mem_ctx, struct wbint_Principal,
394 r->in.rids->num_rids);
395 if (result == NULL) {
396 return NT_STATUS_NO_MEMORY;
399 for (i=0; i<r->in.rids->num_rids; i++) {
400 sid_compose(&result[i].sid, &domain->sid, r->in.rids->rids[i]);
401 result[i].type = types[i];
402 result[i].name = talloc_move(result, &names[i]);
407 r->out.names->num_principals = r->in.rids->num_rids;
408 r->out.names->principals = result;
412 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
413 struct wbint_CheckMachineAccount *r)
415 struct winbindd_domain *domain;
419 domain = wb_child_domain();
420 if (domain == NULL) {
421 return NT_STATUS_REQUEST_NOT_ACCEPTED;
425 invalidate_cm_connection(&domain->conn);
428 struct rpc_pipe_client *netlogon_pipe;
429 status = cm_connect_netlogon(domain, &netlogon_pipe);
432 /* There is a race condition between fetching the trust account
433 password and the periodic machine password change. So it's
434 possible that the trust account password has been changed on us.
435 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
437 #define MAX_RETRIES 3
439 if ((num_retries < MAX_RETRIES)
440 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
445 if (!NT_STATUS_IS_OK(status)) {
446 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
450 /* Pass back result code - zero for success, other values for
451 specific failures. */
453 DEBUG(3,("domain %s secret is %s\n", domain->name,
454 NT_STATUS_IS_OK(status) ? "good" : "bad"));
457 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
458 ("Checking the trust account password for domain %s returned %s\n",
459 domain->name, nt_errstr(status)));
464 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
465 struct wbint_ChangeMachineAccount *r)
467 struct winbindd_domain *domain;
470 struct rpc_pipe_client *netlogon_pipe;
474 domain = wb_child_domain();
475 if (domain == NULL) {
476 return NT_STATUS_REQUEST_NOT_ACCEPTED;
479 invalidate_cm_connection(&domain->conn);
482 status = cm_connect_netlogon(domain, &netlogon_pipe);
485 /* There is a race condition between fetching the trust account
486 password and the periodic machine password change. So it's
487 possible that the trust account password has been changed on us.
488 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
490 #define MAX_RETRIES 3
492 if ((num_retries < MAX_RETRIES)
493 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
498 if (!NT_STATUS_IS_OK(status)) {
499 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
503 tmp_ctx = talloc_new(p->mem_ctx);
505 status = trust_pw_find_change_and_store_it(netlogon_pipe,
508 talloc_destroy(tmp_ctx);
510 /* Pass back result code - zero for success, other values for
511 specific failures. */
513 DEBUG(3,("domain %s secret %s\n", domain->name,
514 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
517 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
518 ("Changing the trust account password for domain %s returned %s\n",
519 domain->name, nt_errstr(status)));
524 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
527 struct winbindd_domain *domain;
528 struct rpc_pipe_client *netlogon_pipe;
529 union netr_CONTROL_QUERY_INFORMATION info;
531 fstring logon_server;
532 struct dcerpc_binding_handle *b;
534 domain = wb_child_domain();
535 if (domain == NULL) {
536 return NT_STATUS_REQUEST_NOT_ACCEPTED;
539 status = cm_connect_netlogon(domain, &netlogon_pipe);
540 if (!NT_STATUS_IS_OK(status)) {
541 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
545 b = netlogon_pipe->binding_handle;
547 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
550 * This provokes a WERR_NOT_SUPPORTED error message. This is
551 * documented in the wspp docs. I could not get a successful
552 * call to work, but the main point here is testing that the
553 * netlogon pipe works.
555 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
556 logon_server, NETLOGON_CONTROL_QUERY,
559 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
560 DEBUG(2, ("dcerpc_netr_LogonControl timed out\n"));
561 invalidate_cm_connection(&domain->conn);
565 if (!NT_STATUS_IS_OK(status)) {
566 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
571 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
572 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
573 "WERR_NOT_SUPPORTED\n",
575 return werror_to_ntstatus(werr);
578 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));