tevent: Add lib/tevent as include directory.
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob850367274c2405080eea8ec0e6cad37736cde340
1 /*
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/>.
23 #include "includes.h"
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "librpc/gen_ndr/srv_wbint.h"
28 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
29 #include "idmap.h"
30 #include "../libcli/security/security.h"
32 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
34 *r->out.out_data = r->in.in_data;
37 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
39 struct winbindd_domain *domain = wb_child_domain();
40 char *dom_name;
41 char *name;
42 enum lsa_SidType type;
43 NTSTATUS status;
45 if (domain == NULL) {
46 return NT_STATUS_REQUEST_NOT_ACCEPTED;
49 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
50 &dom_name, &name, &type);
51 if (!NT_STATUS_IS_OK(status)) {
52 return status;
55 *r->out.domain = dom_name;
56 *r->out.name = name;
57 *r->out.type = type;
58 return NT_STATUS_OK;
61 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
63 struct winbindd_domain *domain = wb_child_domain();
65 if (domain == NULL) {
66 return NT_STATUS_REQUEST_NOT_ACCEPTED;
69 return domain->methods->name_to_sid(
70 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
71 r->out.sid, r->out.type);
74 NTSTATUS _wbint_Sid2Uid(struct pipes_struct *p, struct wbint_Sid2Uid *r)
76 uid_t uid;
77 NTSTATUS status;
79 status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
80 r->in.sid, &uid);
81 if (!NT_STATUS_IS_OK(status)) {
82 return status;
84 *r->out.uid = uid;
85 return NT_STATUS_OK;
88 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
90 gid_t gid;
91 NTSTATUS status;
93 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
94 r->in.sid, &gid);
95 if (!NT_STATUS_IS_OK(status)) {
96 return status;
98 *r->out.gid = gid;
99 return NT_STATUS_OK;
102 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
104 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
105 r->out.sid, r->in.uid);
108 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
110 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
111 r->out.sid, r->in.gid);
114 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
116 struct unixid xid;
117 NTSTATUS status;
119 status = idmap_allocate_uid(&xid);
120 if (!NT_STATUS_IS_OK(status)) {
121 return status;
123 *r->out.uid = xid.id;
124 return NT_STATUS_OK;
127 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
129 struct unixid xid;
130 NTSTATUS status;
132 status = idmap_allocate_gid(&xid);
133 if (!NT_STATUS_IS_OK(status)) {
134 return status;
136 *r->out.gid = xid.id;
137 return NT_STATUS_OK;
140 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
142 struct winbindd_domain *domain = wb_child_domain();
144 if (domain == NULL) {
145 return NT_STATUS_REQUEST_NOT_ACCEPTED;
148 return domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
149 r->out.info);
152 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
153 struct wbint_LookupUserAliases *r)
155 struct winbindd_domain *domain = wb_child_domain();
157 if (domain == NULL) {
158 return NT_STATUS_REQUEST_NOT_ACCEPTED;
161 return domain->methods->lookup_useraliases(
162 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
163 &r->out.rids->num_rids, &r->out.rids->rids);
166 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
167 struct wbint_LookupUserGroups *r)
169 struct winbindd_domain *domain = wb_child_domain();
171 if (domain == NULL) {
172 return NT_STATUS_REQUEST_NOT_ACCEPTED;
175 return domain->methods->lookup_usergroups(
176 domain, p->mem_ctx, r->in.sid,
177 &r->out.sids->num_sids, &r->out.sids->sids);
180 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
181 struct wbint_QuerySequenceNumber *r)
183 struct winbindd_domain *domain = wb_child_domain();
185 if (domain == NULL) {
186 return NT_STATUS_REQUEST_NOT_ACCEPTED;
189 return domain->methods->sequence_number(domain, r->out.sequence);
192 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
193 struct wbint_LookupGroupMembers *r)
195 struct winbindd_domain *domain = wb_child_domain();
196 uint32_t i, num_names;
197 struct dom_sid *sid_mem;
198 char **names;
199 uint32_t *name_types;
200 NTSTATUS status;
202 if (domain == NULL) {
203 return NT_STATUS_REQUEST_NOT_ACCEPTED;
206 status = domain->methods->lookup_groupmem(
207 domain, p->mem_ctx, r->in.sid, r->in.type,
208 &num_names, &sid_mem, &names, &name_types);
209 if (!NT_STATUS_IS_OK(status)) {
210 return status;
213 r->out.members->num_principals = num_names;
214 r->out.members->principals = talloc_array(
215 r->out.members, struct wbint_Principal, num_names);
216 if (r->out.members->principals == NULL) {
217 return NT_STATUS_NO_MEMORY;
220 for (i=0; i<num_names; i++) {
221 struct wbint_Principal *m = &r->out.members->principals[i];
222 sid_copy(&m->sid, &sid_mem[i]);
223 m->name = talloc_move(r->out.members->principals, &names[i]);
224 m->type = (enum lsa_SidType)name_types[i];
227 return NT_STATUS_OK;
230 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
231 struct wbint_QueryUserList *r)
233 struct winbindd_domain *domain = wb_child_domain();
235 if (domain == NULL) {
236 return NT_STATUS_REQUEST_NOT_ACCEPTED;
239 return domain->methods->query_user_list(
240 domain, p->mem_ctx, &r->out.users->num_userinfos,
241 &r->out.users->userinfos);
244 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
245 struct wbint_QueryGroupList *r)
247 struct winbindd_domain *domain = wb_child_domain();
248 uint32_t i, num_groups;
249 struct acct_info *groups;
250 struct wbint_Principal *result;
251 NTSTATUS status;
253 if (domain == NULL) {
254 return NT_STATUS_REQUEST_NOT_ACCEPTED;
257 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
258 &num_groups, &groups);
259 if (!NT_STATUS_IS_OK(status)) {
260 return status;
263 result = talloc_array(r->out.groups, struct wbint_Principal,
264 num_groups);
265 if (result == NULL) {
266 return NT_STATUS_NO_MEMORY;
269 for (i=0; i<num_groups; i++) {
270 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
271 result[i].type = SID_NAME_DOM_GRP;
272 result[i].name = talloc_strdup(result, groups[i].acct_name);
273 if (result[i].name == NULL) {
274 TALLOC_FREE(result);
275 TALLOC_FREE(groups);
276 return NT_STATUS_NO_MEMORY;
280 r->out.groups->num_principals = num_groups;
281 r->out.groups->principals = result;
283 TALLOC_FREE(groups);
284 return NT_STATUS_OK;
287 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
289 struct winbindd_domain *domain = wb_child_domain();
290 struct rpc_pipe_client *netlogon_pipe;
291 struct netr_DsRGetDCNameInfo *dc_info;
292 NTSTATUS status;
293 WERROR werr;
294 unsigned int orig_timeout;
295 struct dcerpc_binding_handle *b;
297 if (domain == NULL) {
298 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
299 r->in.domain_name, r->in.domain_guid,
300 r->in.site_name ? r->in.site_name : "",
301 r->in.flags,
302 r->out.dc_info);
305 status = cm_connect_netlogon(domain, &netlogon_pipe);
307 if (!NT_STATUS_IS_OK(status)) {
308 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
309 return status;
312 b = netlogon_pipe->binding_handle;
314 /* This call can take a long time - allow the server to time out.
315 35 seconds should do it. */
317 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
319 if (domain->active_directory) {
320 status = dcerpc_netr_DsRGetDCName(b,
321 p->mem_ctx, domain->dcname,
322 r->in.domain_name, NULL, r->in.domain_guid,
323 r->in.flags, r->out.dc_info, &werr);
324 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
325 goto done;
330 * Fallback to less capable methods
333 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
334 if (dc_info == NULL) {
335 status = NT_STATUS_NO_MEMORY;
336 goto done;
339 if (r->in.flags & DS_PDC_REQUIRED) {
340 status = dcerpc_netr_GetDcName(b,
341 p->mem_ctx, domain->dcname,
342 r->in.domain_name, &dc_info->dc_unc, &werr);
343 } else {
344 status = dcerpc_netr_GetAnyDCName(b,
345 p->mem_ctx, domain->dcname,
346 r->in.domain_name, &dc_info->dc_unc, &werr);
349 if (!NT_STATUS_IS_OK(status)) {
350 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
351 nt_errstr(status)));
352 goto done;
354 if (!W_ERROR_IS_OK(werr)) {
355 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
356 win_errstr(werr)));
357 status = werror_to_ntstatus(werr);
358 goto done;
361 *r->out.dc_info = dc_info;
362 status = NT_STATUS_OK;
364 done:
365 /* And restore our original timeout. */
366 rpccli_set_timeout(netlogon_pipe, orig_timeout);
368 return status;
371 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
373 struct winbindd_domain *domain = wb_child_domain();
374 char *domain_name;
375 char **names;
376 enum lsa_SidType *types;
377 struct wbint_Principal *result;
378 NTSTATUS status;
379 int i;
381 if (domain == NULL) {
382 return NT_STATUS_REQUEST_NOT_ACCEPTED;
385 status = domain->methods->rids_to_names(
386 domain, talloc_tos(), &domain->sid, r->in.rids->rids,
387 r->in.rids->num_rids, &domain_name, &names, &types);
388 if (!NT_STATUS_IS_OK(status)) {
389 return status;
392 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
394 result = talloc_array(p->mem_ctx, struct wbint_Principal,
395 r->in.rids->num_rids);
396 if (result == NULL) {
397 return NT_STATUS_NO_MEMORY;
400 for (i=0; i<r->in.rids->num_rids; i++) {
401 sid_compose(&result[i].sid, &domain->sid, r->in.rids->rids[i]);
402 result[i].type = types[i];
403 result[i].name = talloc_move(result, &names[i]);
405 TALLOC_FREE(types);
406 TALLOC_FREE(names);
408 r->out.names->num_principals = r->in.rids->num_rids;
409 r->out.names->principals = result;
410 return NT_STATUS_OK;
413 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
414 struct wbint_CheckMachineAccount *r)
416 struct winbindd_domain *domain;
417 int num_retries = 0;
418 NTSTATUS status;
420 domain = wb_child_domain();
421 if (domain == NULL) {
422 return NT_STATUS_REQUEST_NOT_ACCEPTED;
425 again:
426 invalidate_cm_connection(&domain->conn);
429 struct rpc_pipe_client *netlogon_pipe;
430 status = cm_connect_netlogon(domain, &netlogon_pipe);
433 /* There is a race condition between fetching the trust account
434 password and the periodic machine password change. So it's
435 possible that the trust account password has been changed on us.
436 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
438 #define MAX_RETRIES 3
440 if ((num_retries < MAX_RETRIES)
441 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
442 num_retries++;
443 goto again;
446 if (!NT_STATUS_IS_OK(status)) {
447 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
448 goto done;
451 /* Pass back result code - zero for success, other values for
452 specific failures. */
454 DEBUG(3,("domain %s secret is %s\n", domain->name,
455 NT_STATUS_IS_OK(status) ? "good" : "bad"));
457 done:
458 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
459 ("Checking the trust account password for domain %s returned %s\n",
460 domain->name, nt_errstr(status)));
462 return status;
465 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
466 struct wbint_ChangeMachineAccount *r)
468 struct winbindd_domain *domain;
469 int num_retries = 0;
470 NTSTATUS status;
471 struct rpc_pipe_client *netlogon_pipe;
472 TALLOC_CTX *tmp_ctx;
474 again:
475 domain = wb_child_domain();
476 if (domain == NULL) {
477 return NT_STATUS_REQUEST_NOT_ACCEPTED;
480 invalidate_cm_connection(&domain->conn);
483 status = cm_connect_netlogon(domain, &netlogon_pipe);
486 /* There is a race condition between fetching the trust account
487 password and the periodic machine password change. So it's
488 possible that the trust account password has been changed on us.
489 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
491 #define MAX_RETRIES 3
493 if ((num_retries < MAX_RETRIES)
494 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
495 num_retries++;
496 goto again;
499 if (!NT_STATUS_IS_OK(status)) {
500 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
501 goto done;
504 tmp_ctx = talloc_new(p->mem_ctx);
506 status = trust_pw_find_change_and_store_it(netlogon_pipe,
507 tmp_ctx,
508 domain->name);
509 talloc_destroy(tmp_ctx);
511 /* Pass back result code - zero for success, other values for
512 specific failures. */
514 DEBUG(3,("domain %s secret %s\n", domain->name,
515 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
517 done:
518 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
519 ("Changing the trust account password for domain %s returned %s\n",
520 domain->name, nt_errstr(status)));
522 return status;
525 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
527 NTSTATUS status;
528 struct winbindd_domain *domain;
529 struct rpc_pipe_client *netlogon_pipe;
530 union netr_CONTROL_QUERY_INFORMATION info;
531 WERROR werr;
532 fstring logon_server;
533 struct dcerpc_binding_handle *b;
535 domain = wb_child_domain();
536 if (domain == NULL) {
537 return NT_STATUS_REQUEST_NOT_ACCEPTED;
540 status = cm_connect_netlogon(domain, &netlogon_pipe);
541 if (!NT_STATUS_IS_OK(status)) {
542 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
543 return status;
546 b = netlogon_pipe->binding_handle;
548 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
551 * This provokes a WERR_NOT_SUPPORTED error message. This is
552 * documented in the wspp docs. I could not get a successful
553 * call to work, but the main point here is testing that the
554 * netlogon pipe works.
556 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
557 logon_server, NETLOGON_CONTROL_QUERY,
558 2, &info, &werr);
560 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
561 DEBUG(2, ("dcerpc_netr_LogonControl timed out\n"));
562 invalidate_cm_connection(&domain->conn);
563 return status;
566 if (!NT_STATUS_IS_OK(status)) {
567 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
568 nt_errstr(status)));
569 return status;
572 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
573 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
574 "WERR_NOT_SUPPORTED\n",
575 win_errstr(werr)));
576 return werror_to_ntstatus(werr);
579 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
580 return NT_STATUS_OK;