s3: Add wbint_Sids2UnixIDs idl & implementation
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob230edae9080b3da88b1c3d69d54eec6b056961ee
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"
31 #include "ntdomain.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();
41 char *dom_name;
42 char *name;
43 enum lsa_SidType type;
44 NTSTATUS status;
46 if (domain == NULL) {
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)) {
53 return status;
56 *r->out.domain = dom_name;
57 *r->out.name = name;
58 *r->out.type = type;
59 return NT_STATUS_OK;
62 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
64 struct winbindd_domain *domain = wb_child_domain();
66 if (domain == NULL) {
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();
84 if (domain == NULL) {
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)
95 uid_t uid;
96 NTSTATUS status;
98 status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
99 r->in.sid, &uid);
100 if (!NT_STATUS_IS_OK(status)) {
101 return status;
103 *r->out.uid = uid;
104 return NT_STATUS_OK;
107 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
109 gid_t gid;
110 NTSTATUS status;
112 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
113 r->in.sid, &gid);
114 if (!NT_STATUS_IS_OK(status)) {
115 return status;
117 *r->out.gid = gid;
118 return NT_STATUS_OK;
121 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
122 struct wbint_Sids2UnixIDs *r)
124 uint32_t i, j;
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;
134 uint32_t num_ids;
136 dom = idmap_find_domain(d->name.string);
137 if (dom == NULL) {
138 DEBUG(10, ("idmap domain %s not found\n",
139 d->name.string));
140 continue;
143 num_ids = 0;
145 for (j=0; j<r->in.ids->num_ids; j++) {
146 if (r->in.ids->ids[j].domain_index == i) {
147 num_ids += 1;
151 ids = TALLOC_REALLOC_ARRAY(talloc_tos(), ids,
152 struct id_map, num_ids);
153 if (ids == NULL) {
154 goto nomem;
156 id_ptrs = TALLOC_REALLOC_ARRAY(talloc_tos(), id_ptrs,
157 struct id_map *, num_ids+1);
158 if (id_ptrs == NULL) {
159 goto nomem;
161 id_idx = TALLOC_REALLOC_ARRAY(talloc_tos(), id_idx,
162 uint32_t, num_ids);
163 if (id_idx == NULL) {
164 goto nomem;
166 sids = TALLOC_REALLOC_ARRAY(talloc_tos(), sids,
167 struct dom_sid, num_ids);
168 if (sids == NULL) {
169 goto nomem;
172 num_ids = 0;
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) {
178 continue;
180 id_idx[num_ids] = j;
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;
187 num_ids += 1;
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",
193 nt_errstr(status)));
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) {
199 continue;
201 id->unix_id = ids[j].xid.id;
204 status = NT_STATUS_OK;
205 nomem:
206 TALLOC_FREE(ids);
207 TALLOC_FREE(id_ptrs);
208 TALLOC_FREE(id_idx);
209 TALLOC_FREE(sids);
210 return status;
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)
227 struct unixid xid;
228 NTSTATUS status;
230 status = idmap_allocate_uid(&xid);
231 if (!NT_STATUS_IS_OK(status)) {
232 return status;
234 *r->out.uid = xid.id;
235 return NT_STATUS_OK;
238 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
240 struct unixid xid;
241 NTSTATUS status;
243 status = idmap_allocate_gid(&xid);
244 if (!NT_STATUS_IS_OK(status)) {
245 return status;
247 *r->out.gid = xid.id;
248 return NT_STATUS_OK;
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,
260 r->out.info);
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;
309 char **names;
310 uint32_t *name_types;
311 NTSTATUS status;
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)) {
321 return 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];
338 return NT_STATUS_OK;
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;
362 NTSTATUS status;
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)) {
371 return status;
374 result = talloc_array(r->out.groups, struct wbint_Principal,
375 num_groups);
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) {
385 TALLOC_FREE(result);
386 TALLOC_FREE(groups);
387 return NT_STATUS_NO_MEMORY;
391 r->out.groups->num_principals = num_groups;
392 r->out.groups->principals = result;
394 TALLOC_FREE(groups);
395 return NT_STATUS_OK;
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;
403 NTSTATUS status;
404 WERROR werr;
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 : "",
412 r->in.flags,
413 r->out.dc_info);
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"));
420 return status;
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)) {
436 goto done;
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;
447 goto done;
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);
454 } else {
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",
462 nt_errstr(status)));
463 goto done;
465 if (!W_ERROR_IS_OK(werr)) {
466 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
467 win_errstr(werr)));
468 status = werror_to_ntstatus(werr);
469 goto done;
472 *r->out.dc_info = dc_info;
473 status = NT_STATUS_OK;
475 done:
476 /* And restore our original timeout. */
477 rpccli_set_timeout(netlogon_pipe, orig_timeout);
479 return status;
482 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
484 struct winbindd_domain *domain = wb_child_domain();
485 char *domain_name;
486 char **names;
487 enum lsa_SidType *types;
488 struct wbint_Principal *result;
489 NTSTATUS status;
490 int i;
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)) {
500 return 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]);
516 TALLOC_FREE(types);
517 TALLOC_FREE(names);
519 r->out.names->num_principals = r->in.rids->num_rids;
520 r->out.names->principals = result;
521 return NT_STATUS_OK;
524 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
525 struct wbint_CheckMachineAccount *r)
527 struct winbindd_domain *domain;
528 int num_retries = 0;
529 NTSTATUS status;
531 domain = wb_child_domain();
532 if (domain == NULL) {
533 return NT_STATUS_REQUEST_NOT_ACCEPTED;
536 again:
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)) {
553 num_retries++;
554 goto again;
557 if (!NT_STATUS_IS_OK(status)) {
558 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
559 goto done;
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"));
568 done:
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)));
573 return status;
576 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
577 struct wbint_ChangeMachineAccount *r)
579 struct winbindd_domain *domain;
580 int num_retries = 0;
581 NTSTATUS status;
582 struct rpc_pipe_client *netlogon_pipe;
583 TALLOC_CTX *tmp_ctx;
585 again:
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)) {
606 num_retries++;
607 goto again;
610 if (!NT_STATUS_IS_OK(status)) {
611 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
612 goto done;
615 tmp_ctx = talloc_new(p->mem_ctx);
617 status = trust_pw_find_change_and_store_it(netlogon_pipe,
618 tmp_ctx,
619 domain->name);
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"));
628 done:
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)));
633 return status;
636 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
638 NTSTATUS status;
639 struct winbindd_domain *domain;
640 struct rpc_pipe_client *netlogon_pipe;
641 union netr_CONTROL_QUERY_INFORMATION info;
642 WERROR werr;
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"));
654 return status;
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,
669 2, &info, &werr);
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);
674 return status;
677 if (!NT_STATUS_IS_OK(status)) {
678 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
679 nt_errstr(status)));
680 return status;
683 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
684 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
685 "WERR_NOT_SUPPORTED\n",
686 win_errstr(werr)));
687 return werror_to_ntstatus(werr);
690 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
691 return NT_STATUS_OK;