s3-spoolss: Don't leak memory.
[Samba/bjacke.git] / source3 / winbindd / winbindd_dual_srv.c
blob5344063f16142639b51efcf2e383dea6f9a5ac3b
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 "ntdomain.h"
28 #include "librpc/gen_ndr/srv_wbint.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "idmap.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 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
39 NTSTATUS status)
41 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
42 invalidate_cm_connection(&domain->conn);
43 /* We invalidated the connection. */
44 return true;
46 return false;
49 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
51 struct winbindd_domain *domain = wb_child_domain();
52 char *dom_name;
53 char *name;
54 enum lsa_SidType type;
55 NTSTATUS status;
57 if (domain == NULL) {
58 return NT_STATUS_REQUEST_NOT_ACCEPTED;
61 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
62 &dom_name, &name, &type);
63 reset_cm_connection_on_error(domain, status);
64 if (!NT_STATUS_IS_OK(status)) {
65 return status;
68 *r->out.domain = dom_name;
69 *r->out.name = name;
70 *r->out.type = type;
71 return NT_STATUS_OK;
74 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
76 struct winbindd_domain *domain = wb_child_domain();
77 NTSTATUS status;
79 if (domain == NULL) {
80 return NT_STATUS_REQUEST_NOT_ACCEPTED;
84 * This breaks the winbindd_domain->methods abstraction: This
85 * is only called for remote domains, and both winbindd_msrpc
86 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
87 * done at the wbint RPC layer.
89 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
90 &r->out.domains, &r->out.names);
91 reset_cm_connection_on_error(domain, status);
92 return status;
95 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
97 struct winbindd_domain *domain = wb_child_domain();
98 NTSTATUS status;
100 if (domain == NULL) {
101 return NT_STATUS_REQUEST_NOT_ACCEPTED;
104 status = domain->methods->name_to_sid(
105 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
106 r->out.sid, r->out.type);
107 reset_cm_connection_on_error(domain, status);
108 return status;
111 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
112 struct wbint_Sids2UnixIDs *r)
114 uint32_t i, j;
115 struct id_map *ids = NULL;
116 struct id_map **id_ptrs = NULL;
117 struct dom_sid *sids = NULL;
118 uint32_t *id_idx = NULL;
119 NTSTATUS status = NT_STATUS_NO_MEMORY;
121 for (i=0; i<r->in.domains->count; i++) {
122 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
123 struct idmap_domain *dom;
124 uint32_t num_ids;
126 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
127 if (dom == NULL) {
128 DEBUG(10, ("idmap domain %s:%s not found\n",
129 d->name.string, sid_string_dbg(d->sid)));
130 continue;
133 num_ids = 0;
135 for (j=0; j<r->in.ids->num_ids; j++) {
136 if (r->in.ids->ids[j].domain_index == i) {
137 num_ids += 1;
141 ids = talloc_realloc(talloc_tos(), ids,
142 struct id_map, num_ids);
143 if (ids == NULL) {
144 goto nomem;
146 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
147 struct id_map *, num_ids+1);
148 if (id_ptrs == NULL) {
149 goto nomem;
151 id_idx = talloc_realloc(talloc_tos(), id_idx,
152 uint32_t, num_ids);
153 if (id_idx == NULL) {
154 goto nomem;
156 sids = talloc_realloc(talloc_tos(), sids,
157 struct dom_sid, num_ids);
158 if (sids == NULL) {
159 goto nomem;
162 num_ids = 0;
165 * Convert the input data into a list of
166 * id_map structs suitable for handing in
167 * to the idmap sids_to_unixids method.
169 for (j=0; j<r->in.ids->num_ids; j++) {
170 struct wbint_TransID *id = &r->in.ids->ids[j];
172 if (id->domain_index != i) {
173 continue;
175 id_idx[num_ids] = j;
176 id_ptrs[num_ids] = &ids[num_ids];
178 ids[num_ids].sid = &sids[num_ids];
179 sid_compose(ids[num_ids].sid, d->sid, id->rid);
180 ids[num_ids].xid.type = id->type;
181 ids[num_ids].status = ID_UNKNOWN;
182 num_ids += 1;
184 id_ptrs[num_ids] = NULL;
186 status = dom->methods->sids_to_unixids(dom, id_ptrs);
187 DEBUG(10, ("sids_to_unixids returned %s\n",
188 nt_errstr(status)));
191 * Extract the results for handing them back to the caller.
193 for (j=0; j<num_ids; j++) {
194 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
196 if (ids[j].status != ID_MAPPED) {
197 id->xid.id = UINT32_MAX;
198 id->xid.type = ID_TYPE_NOT_SPECIFIED;
199 continue;
202 id->xid = ids[j].xid;
205 status = NT_STATUS_OK;
206 nomem:
207 TALLOC_FREE(ids);
208 TALLOC_FREE(id_ptrs);
209 TALLOC_FREE(id_idx);
210 TALLOC_FREE(sids);
211 return status;
214 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
216 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
217 r->out.sid, r->in.uid);
220 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
222 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
223 r->out.sid, r->in.gid);
226 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
228 struct unixid xid;
229 NTSTATUS status;
231 status = idmap_allocate_uid(&xid);
232 if (!NT_STATUS_IS_OK(status)) {
233 return status;
235 *r->out.uid = xid.id;
236 return NT_STATUS_OK;
239 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
241 struct unixid xid;
242 NTSTATUS status;
244 status = idmap_allocate_gid(&xid);
245 if (!NT_STATUS_IS_OK(status)) {
246 return status;
248 *r->out.gid = xid.id;
249 return NT_STATUS_OK;
252 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
254 struct winbindd_domain *domain = wb_child_domain();
255 NTSTATUS status;
257 if (domain == NULL) {
258 return NT_STATUS_REQUEST_NOT_ACCEPTED;
261 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
262 r->out.info);
263 reset_cm_connection_on_error(domain, status);
264 return status;
267 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
268 struct wbint_LookupUserAliases *r)
270 struct winbindd_domain *domain = wb_child_domain();
271 NTSTATUS status;
273 if (domain == NULL) {
274 return NT_STATUS_REQUEST_NOT_ACCEPTED;
277 status = domain->methods->lookup_useraliases(
278 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
279 &r->out.rids->num_rids, &r->out.rids->rids);
280 reset_cm_connection_on_error(domain, status);
281 return status;
284 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
285 struct wbint_LookupUserGroups *r)
287 struct winbindd_domain *domain = wb_child_domain();
288 NTSTATUS status;
290 if (domain == NULL) {
291 return NT_STATUS_REQUEST_NOT_ACCEPTED;
294 status = domain->methods->lookup_usergroups(
295 domain, p->mem_ctx, r->in.sid,
296 &r->out.sids->num_sids, &r->out.sids->sids);
297 reset_cm_connection_on_error(domain, status);
298 return status;
301 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
302 struct wbint_QuerySequenceNumber *r)
304 struct winbindd_domain *domain = wb_child_domain();
305 NTSTATUS status;
307 if (domain == NULL) {
308 return NT_STATUS_REQUEST_NOT_ACCEPTED;
311 status = domain->methods->sequence_number(domain, r->out.sequence);
312 reset_cm_connection_on_error(domain, status);
313 return status;
316 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
317 struct wbint_LookupGroupMembers *r)
319 struct winbindd_domain *domain = wb_child_domain();
320 uint32_t i, num_names;
321 struct dom_sid *sid_mem;
322 char **names;
323 uint32_t *name_types;
324 NTSTATUS status;
326 if (domain == NULL) {
327 return NT_STATUS_REQUEST_NOT_ACCEPTED;
330 status = domain->methods->lookup_groupmem(
331 domain, p->mem_ctx, r->in.sid, r->in.type,
332 &num_names, &sid_mem, &names, &name_types);
333 reset_cm_connection_on_error(domain, status);
334 if (!NT_STATUS_IS_OK(status)) {
335 return status;
338 r->out.members->num_principals = num_names;
339 r->out.members->principals = talloc_array(
340 r->out.members, struct wbint_Principal, num_names);
341 if (r->out.members->principals == NULL) {
342 return NT_STATUS_NO_MEMORY;
345 for (i=0; i<num_names; i++) {
346 struct wbint_Principal *m = &r->out.members->principals[i];
347 sid_copy(&m->sid, &sid_mem[i]);
348 m->name = talloc_move(r->out.members->principals, &names[i]);
349 m->type = (enum lsa_SidType)name_types[i];
352 return NT_STATUS_OK;
355 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
356 struct wbint_QueryUserList *r)
358 struct winbindd_domain *domain = wb_child_domain();
359 NTSTATUS status;
361 if (domain == NULL) {
362 return NT_STATUS_REQUEST_NOT_ACCEPTED;
365 status = domain->methods->query_user_list(
366 domain, p->mem_ctx, &r->out.users->num_userinfos,
367 &r->out.users->userinfos);
368 reset_cm_connection_on_error(domain, status);
369 return status;
372 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
373 struct wbint_QueryGroupList *r)
375 struct winbindd_domain *domain = wb_child_domain();
376 uint32_t i, num_groups;
377 struct wb_acct_info *groups;
378 struct wbint_Principal *result;
379 NTSTATUS status;
381 if (domain == NULL) {
382 return NT_STATUS_REQUEST_NOT_ACCEPTED;
385 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
386 &num_groups, &groups);
387 reset_cm_connection_on_error(domain, status);
388 if (!NT_STATUS_IS_OK(status)) {
389 return status;
392 result = talloc_array(r->out.groups, struct wbint_Principal,
393 num_groups);
394 if (result == NULL) {
395 return NT_STATUS_NO_MEMORY;
398 for (i=0; i<num_groups; i++) {
399 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
400 result[i].type = SID_NAME_DOM_GRP;
401 result[i].name = talloc_strdup(result, groups[i].acct_name);
402 if (result[i].name == NULL) {
403 TALLOC_FREE(result);
404 TALLOC_FREE(groups);
405 return NT_STATUS_NO_MEMORY;
409 r->out.groups->num_principals = num_groups;
410 r->out.groups->principals = result;
412 TALLOC_FREE(groups);
413 return NT_STATUS_OK;
416 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
418 struct winbindd_domain *domain = wb_child_domain();
419 struct rpc_pipe_client *netlogon_pipe;
420 struct netr_DsRGetDCNameInfo *dc_info;
421 NTSTATUS status;
422 WERROR werr;
423 unsigned int orig_timeout;
424 struct dcerpc_binding_handle *b;
426 if (domain == NULL) {
427 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
428 r->in.domain_name, r->in.domain_guid,
429 r->in.site_name ? r->in.site_name : "",
430 r->in.flags,
431 r->out.dc_info);
434 status = cm_connect_netlogon(domain, &netlogon_pipe);
436 reset_cm_connection_on_error(domain, status);
437 if (!NT_STATUS_IS_OK(status)) {
438 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
439 return status;
442 b = netlogon_pipe->binding_handle;
444 /* This call can take a long time - allow the server to time out.
445 35 seconds should do it. */
447 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
449 if (domain->active_directory) {
450 status = dcerpc_netr_DsRGetDCName(b,
451 p->mem_ctx, domain->dcname,
452 r->in.domain_name, NULL, r->in.domain_guid,
453 r->in.flags, r->out.dc_info, &werr);
454 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
455 goto done;
457 if (reset_cm_connection_on_error(domain, status)) {
458 /* Re-initialize. */
459 status = cm_connect_netlogon(domain, &netlogon_pipe);
461 reset_cm_connection_on_error(domain, status);
462 if (!NT_STATUS_IS_OK(status)) {
463 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
464 return status;
467 b = netlogon_pipe->binding_handle;
469 /* This call can take a long time - allow the server to time out.
470 35 seconds should do it. */
472 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
477 * Fallback to less capable methods
480 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
481 if (dc_info == NULL) {
482 status = NT_STATUS_NO_MEMORY;
483 goto done;
486 if (r->in.flags & DS_PDC_REQUIRED) {
487 status = dcerpc_netr_GetDcName(b,
488 p->mem_ctx, domain->dcname,
489 r->in.domain_name, &dc_info->dc_unc, &werr);
490 } else {
491 status = dcerpc_netr_GetAnyDCName(b,
492 p->mem_ctx, domain->dcname,
493 r->in.domain_name, &dc_info->dc_unc, &werr);
496 reset_cm_connection_on_error(domain, status);
497 if (!NT_STATUS_IS_OK(status)) {
498 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
499 nt_errstr(status)));
500 goto done;
502 if (!W_ERROR_IS_OK(werr)) {
503 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
504 win_errstr(werr)));
505 status = werror_to_ntstatus(werr);
506 goto done;
509 *r->out.dc_info = dc_info;
510 status = NT_STATUS_OK;
512 done:
513 /* And restore our original timeout. */
514 rpccli_set_timeout(netlogon_pipe, orig_timeout);
516 return status;
519 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
521 struct winbindd_domain *domain = wb_child_domain();
522 char *domain_name;
523 char **names;
524 enum lsa_SidType *types;
525 struct wbint_Principal *result;
526 NTSTATUS status;
527 int i;
529 if (domain == NULL) {
530 return NT_STATUS_REQUEST_NOT_ACCEPTED;
533 status = domain->methods->rids_to_names(
534 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
535 r->in.rids->num_rids, &domain_name, &names, &types);
536 reset_cm_connection_on_error(domain, status);
537 if (!NT_STATUS_IS_OK(status)) {
538 return status;
541 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
543 result = talloc_array(p->mem_ctx, struct wbint_Principal,
544 r->in.rids->num_rids);
545 if (result == NULL) {
546 return NT_STATUS_NO_MEMORY;
549 for (i=0; i<r->in.rids->num_rids; i++) {
550 sid_compose(&result[i].sid, r->in.domain_sid,
551 r->in.rids->rids[i]);
552 result[i].type = types[i];
553 result[i].name = talloc_move(result, &names[i]);
555 TALLOC_FREE(types);
556 TALLOC_FREE(names);
558 r->out.names->num_principals = r->in.rids->num_rids;
559 r->out.names->principals = result;
560 return NT_STATUS_OK;
563 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
564 struct wbint_CheckMachineAccount *r)
566 struct winbindd_domain *domain;
567 int num_retries = 0;
568 NTSTATUS status;
570 domain = wb_child_domain();
571 if (domain == NULL) {
572 return NT_STATUS_REQUEST_NOT_ACCEPTED;
575 again:
576 invalidate_cm_connection(&domain->conn);
579 struct rpc_pipe_client *netlogon_pipe;
580 status = cm_connect_netlogon(domain, &netlogon_pipe);
583 /* There is a race condition between fetching the trust account
584 password and the periodic machine password change. So it's
585 possible that the trust account password has been changed on us.
586 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
588 #define MAX_RETRIES 3
590 if ((num_retries < MAX_RETRIES)
591 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
592 num_retries++;
593 goto again;
596 if (!NT_STATUS_IS_OK(status)) {
597 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
598 goto done;
601 /* Pass back result code - zero for success, other values for
602 specific failures. */
604 DEBUG(3,("domain %s secret is %s\n", domain->name,
605 NT_STATUS_IS_OK(status) ? "good" : "bad"));
607 done:
608 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
609 ("Checking the trust account password for domain %s returned %s\n",
610 domain->name, nt_errstr(status)));
612 return status;
615 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
616 struct wbint_ChangeMachineAccount *r)
618 struct winbindd_domain *domain;
619 int num_retries = 0;
620 NTSTATUS status;
621 struct rpc_pipe_client *netlogon_pipe;
622 TALLOC_CTX *tmp_ctx;
624 again:
625 domain = wb_child_domain();
626 if (domain == NULL) {
627 return NT_STATUS_REQUEST_NOT_ACCEPTED;
630 invalidate_cm_connection(&domain->conn);
633 status = cm_connect_netlogon(domain, &netlogon_pipe);
636 /* There is a race condition between fetching the trust account
637 password and the periodic machine password change. So it's
638 possible that the trust account password has been changed on us.
639 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
641 #define MAX_RETRIES 3
643 if ((num_retries < MAX_RETRIES)
644 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
645 num_retries++;
646 goto again;
649 if (!NT_STATUS_IS_OK(status)) {
650 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
651 goto done;
654 tmp_ctx = talloc_new(p->mem_ctx);
656 status = trust_pw_find_change_and_store_it(netlogon_pipe,
657 tmp_ctx,
658 domain->name);
659 talloc_destroy(tmp_ctx);
661 /* Pass back result code - zero for success, other values for
662 specific failures. */
664 DEBUG(3,("domain %s secret %s\n", domain->name,
665 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
667 done:
668 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
669 ("Changing the trust account password for domain %s returned %s\n",
670 domain->name, nt_errstr(status)));
672 return status;
675 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
677 NTSTATUS status;
678 struct winbindd_domain *domain;
679 struct rpc_pipe_client *netlogon_pipe;
680 union netr_CONTROL_QUERY_INFORMATION info;
681 WERROR werr;
682 fstring logon_server;
683 struct dcerpc_binding_handle *b;
685 domain = wb_child_domain();
686 if (domain == NULL) {
687 return NT_STATUS_REQUEST_NOT_ACCEPTED;
690 status = cm_connect_netlogon(domain, &netlogon_pipe);
691 reset_cm_connection_on_error(domain, status);
692 if (!NT_STATUS_IS_OK(status)) {
693 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
694 return status;
697 b = netlogon_pipe->binding_handle;
699 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
700 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
701 if (r->out.dcname == NULL) {
702 DEBUG(2, ("Could not allocate memory\n"));
703 return NT_STATUS_NO_MEMORY;
707 * This provokes a WERR_NOT_SUPPORTED error message. This is
708 * documented in the wspp docs. I could not get a successful
709 * call to work, but the main point here is testing that the
710 * netlogon pipe works.
712 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
713 logon_server, NETLOGON_CONTROL_QUERY,
714 2, &info, &werr);
716 reset_cm_connection_on_error(domain, status);
717 if (!NT_STATUS_IS_OK(status)) {
718 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
719 nt_errstr(status)));
720 return status;
723 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
724 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
725 "WERR_NOT_SUPPORTED\n",
726 win_errstr(werr)));
727 return werror_to_ntstatus(werr);
730 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
731 return NT_STATUS_OK;