winbindd_irpc: Add an IRPC call to trigger a DC locate
[sfrench/samba-autobuild/.git] / source3 / winbindd / winbindd_irpc.c
1 /*
2    Unix SMB/CIFS implementation.
3    async implementation of commands submitted over IRPC
4    Copyright (C) Volker Lendecke 2009
5    Copyright (C) Guenther Deschner 2009
6    Copyright (C) Andrew Bartlett 2014
7    Copyright (C) Andrew Tridgell 2009
8
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.
13
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.
18
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/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25 #include "librpc/gen_ndr/ndr_winbind_c.h"
26 #include "source4/lib/messaging/irpc.h"
27 #include "librpc/gen_ndr/ndr_winbind.h"
28 #include "librpc/gen_ndr/ndr_lsa.h"
29 #include "librpc/gen_ndr/ndr_lsa_c.h"
30 #include "libcli/security/dom_sid.h"
31 #include "passdb/lookup_sid.h" /* only for LOOKUP_NAME_NO_NSS flag */
32 #include "librpc/gen_ndr/ndr_irpc.h"
33 #include "librpc/gen_ndr/ndr_netlogon.h"
34
35 struct wb_irpc_forward_state {
36         struct irpc_message *msg;
37         struct winbind_DsrUpdateReadOnlyServerDnsRecords *req;
38
39         const char *opname;
40         struct dcesrv_call_state *dce_call;
41 };
42
43 /*
44   called when the forwarded rpc request is finished
45  */
46 static void wb_irpc_forward_callback(struct tevent_req *subreq)
47 {
48         struct wb_irpc_forward_state *st =
49                 tevent_req_callback_data(subreq,
50                 struct wb_irpc_forward_state);
51         const char *opname = st->opname;
52         NTSTATUS status;
53
54         status = dcerpc_binding_handle_call_recv(subreq);
55         TALLOC_FREE(subreq);
56         if (!NT_STATUS_IS_OK(status)) {
57                 DEBUG(0,("RPC callback failed for %s - %s\n",
58                          opname, nt_errstr(status)));
59                 irpc_send_reply(st->msg, status);
60                 return;
61         }
62
63         irpc_send_reply(st->msg, status);
64 }
65
66
67
68 /**
69  * Forward a RPC call using IRPC to another task
70  */
71
72 static NTSTATUS wb_irpc_forward_rpc_call(struct irpc_message *msg, TALLOC_CTX *mem_ctx,
73                                          struct tevent_context *ev,
74                                          void *r, uint32_t callid,
75                                          const char *opname,
76                                          struct winbindd_domain *domain,
77                                          uint32_t timeout)
78 {
79         struct wb_irpc_forward_state *st;
80         struct dcerpc_binding_handle *binding_handle;
81         struct tevent_req *subreq;
82
83         st = talloc(mem_ctx, struct wb_irpc_forward_state);
84         if (st == NULL) {
85                 return NT_STATUS_NO_MEMORY;
86         }
87
88         st->msg = msg;
89         st->opname   = opname;
90
91         binding_handle =  dom_child_handle(domain);
92         if (binding_handle == NULL) {
93                 DEBUG(0,("%s: Failed to forward request to winbind handler for %s\n",
94                          opname, domain->name));
95                 return NT_STATUS_UNSUCCESSFUL;
96         }
97
98         /* reset timeout for the handle */
99         dcerpc_binding_handle_set_timeout(binding_handle, timeout);
100
101         /* forward the call */
102         subreq = dcerpc_binding_handle_call_send(st, ev,
103                                                  binding_handle,
104                                                  NULL, &ndr_table_winbind,
105                                                  callid,
106                                                  msg, r);
107         if (subreq == NULL) {
108                 DEBUG(0,("%s: Failed to forward request to winbind handler for %s\n",
109                          opname, domain->name));
110                 return NT_STATUS_UNSUCCESSFUL;
111         }
112
113         /* mark the request as replied async */
114         msg->defer_reply = true;
115
116         /* setup the callback */
117         tevent_req_set_callback(subreq, wb_irpc_forward_callback, st);
118         return NT_STATUS_OK;
119 }
120
121 static NTSTATUS wb_irpc_DsrUpdateReadOnlyServerDnsRecords(struct irpc_message *msg,
122                                                    struct winbind_DsrUpdateReadOnlyServerDnsRecords *req)
123 {
124         struct winbindd_domain *domain = find_our_domain();
125         if (domain == NULL) {
126                 return NT_STATUS_NO_SUCH_DOMAIN;
127         }
128
129         DEBUG(5, ("wb_irpc_DsrUpdateReadOnlyServerDnsRecords called\n"));
130
131         return wb_irpc_forward_rpc_call(msg, msg,
132                                         server_event_context(),
133                                         req, NDR_WINBIND_DSRUPDATEREADONLYSERVERDNSRECORDS,
134                                         "winbind_DsrUpdateReadOnlyServerDnsRecords",
135                                         domain, IRPC_CALL_TIMEOUT);
136 }
137
138 static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
139                                  struct winbind_SamLogon *req)
140 {
141         struct winbindd_domain *domain;
142         struct netr_IdentityInfo *identity_info;
143         const char *target_domain_name = NULL;
144         const char *account_name = NULL;
145
146         switch (req->in.logon_level) {
147         case NetlogonInteractiveInformation:
148         case NetlogonServiceInformation:
149         case NetlogonInteractiveTransitiveInformation:
150         case NetlogonServiceTransitiveInformation:
151                 if (req->in.logon.password == NULL) {
152                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
153                 }
154                 identity_info = &req->in.logon.password->identity_info;
155                 break;
156
157         case NetlogonNetworkInformation:
158         case NetlogonNetworkTransitiveInformation:
159                 if (req->in.logon.network == NULL) {
160                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
161                 }
162
163                 identity_info = &req->in.logon.network->identity_info;
164                 break;
165
166         case NetlogonGenericInformation:
167                 if (req->in.logon.generic == NULL) {
168                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
169                 }
170
171                 identity_info = &req->in.logon.generic->identity_info;
172                 break;
173
174         default:
175                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
176         }
177
178         target_domain_name = identity_info->domain_name.string;
179         if (target_domain_name == NULL) {
180                 target_domain_name = "";
181         }
182
183         account_name = identity_info->account_name.string;
184         if (account_name == NULL) {
185                 account_name = "";
186         }
187
188         if (IS_DC && target_domain_name[0] == '\0') {
189                 const char *p = NULL;
190
191                 p = strchr_m(account_name, '@');
192                 if (p != NULL) {
193                         target_domain_name = p + 1;
194                 }
195         }
196
197         if (IS_DC && target_domain_name[0] == '\0') {
198                 DBG_ERR("target_domain[%s] account[%s]\n",
199                         target_domain_name, account_name);
200                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
201         }
202
203         domain = find_auth_domain(0, target_domain_name);
204         if (domain == NULL) {
205                 DBG_INFO("target_domain[%s] for account[%s] not known\n",
206                         target_domain_name, account_name);
207                 req->out.result = NT_STATUS_NO_SUCH_USER;
208                 req->out.authoritative = 0;
209                 return NT_STATUS_OK;
210         }
211
212         DEBUG(5, ("wb_irpc_SamLogon called\n"));
213
214         return wb_irpc_forward_rpc_call(msg, msg,
215                                         server_event_context(),
216                                         req, NDR_WINBIND_SAMLOGON,
217                                         "winbind_SamLogon",
218                                         domain, IRPC_CALL_TIMEOUT);
219 }
220
221 static NTSTATUS wb_irpc_LogonControl(struct irpc_message *msg,
222                                      struct winbind_LogonControl *req)
223 {
224         TALLOC_CTX *frame = talloc_stackframe();
225         char *domain_name = NULL;
226         struct winbindd_domain *domain = NULL;
227
228         DEBUG(5, ("wb_irpc_LogonControl called\n"));
229
230         switch (req->in.function_code) {
231         case NETLOGON_CONTROL_REDISCOVER:
232         case NETLOGON_CONTROL_TC_QUERY:
233         case NETLOGON_CONTROL_CHANGE_PASSWORD:
234         case NETLOGON_CONTROL_TC_VERIFY:
235                 if (req->in.data->domain == NULL) {
236                         TALLOC_FREE(frame);
237                         return NT_STATUS_INVALID_PARAMETER;
238                 }
239
240                 domain_name = talloc_strdup(frame, req->in.data->domain);
241                 if (domain_name == NULL) {
242                         req->out.result = WERR_NOT_ENOUGH_MEMORY;
243                         TALLOC_FREE(frame);
244                         return NT_STATUS_OK;
245                 }
246
247                 break;
248         default:
249                 TALLOC_FREE(frame);
250                 return NT_STATUS_NOT_IMPLEMENTED;
251         }
252
253         if (req->in.function_code == NETLOGON_CONTROL_REDISCOVER) {
254                 char *p = NULL;
255
256                 /*
257                  * NETLOGON_CONTROL_REDISCOVER
258                  * get's an optional \dcname appended to the domain name
259                  */
260                 p = strchr_m(domain_name, '\\');
261                 if (p != NULL) {
262                         *p = '\0';
263                 }
264         }
265
266         domain = find_domain_from_name_noinit(domain_name);
267         if (domain == NULL) {
268                 req->out.result = WERR_NO_SUCH_DOMAIN;
269                 TALLOC_FREE(frame);
270                 return NT_STATUS_OK;
271         }
272
273         TALLOC_FREE(frame);
274         return wb_irpc_forward_rpc_call(msg, msg,
275                                         server_event_context(),
276                                         req, NDR_WINBIND_LOGONCONTROL,
277                                         "winbind_LogonControl",
278                                         domain, 45 /* timeout */);
279 }
280
281 static NTSTATUS wb_irpc_GetForestTrustInformation(struct irpc_message *msg,
282                                      struct winbind_GetForestTrustInformation *req)
283 {
284         struct winbindd_domain *domain = NULL;
285
286         if (req->in.trusted_domain_name == NULL) {
287                 req->out.result = WERR_NO_SUCH_DOMAIN;
288                 return NT_STATUS_OK;
289         }
290
291         domain = find_trust_from_name_noinit(req->in.trusted_domain_name);
292         if (domain == NULL) {
293                 req->out.result = WERR_NO_SUCH_DOMAIN;
294                 return NT_STATUS_OK;
295         }
296
297         /*
298          * checking for domain->internal and domain->primary
299          * makes sure we only do some work when running as DC.
300          */
301
302         if (domain->internal) {
303                 req->out.result = WERR_NO_SUCH_DOMAIN;
304                 return NT_STATUS_OK;
305         }
306
307         if (domain->primary) {
308                 req->out.result = WERR_NO_SUCH_DOMAIN;
309                 return NT_STATUS_OK;
310         }
311
312         DEBUG(5, ("wb_irpc_GetForestTrustInformation called\n"));
313
314         return wb_irpc_forward_rpc_call(msg, msg,
315                                         server_event_context(),
316                                         req, NDR_WINBIND_GETFORESTTRUSTINFORMATION,
317                                         "winbind_GetForestTrustInformation",
318                                         domain, 45 /* timeout */);
319 }
320
321 static NTSTATUS wb_irpc_SendToSam(struct irpc_message *msg,
322                                   struct winbind_SendToSam *req)
323 {
324         /* TODO make sure that it is RWDC */
325         struct winbindd_domain *domain = find_our_domain();
326         if (domain == NULL) {
327                 return NT_STATUS_NO_SUCH_DOMAIN;
328         }
329
330         DEBUG(5, ("wb_irpc_SendToSam called\n"));
331
332         return wb_irpc_forward_rpc_call(msg, msg,
333                                         server_event_context(),
334                                         req, NDR_WINBIND_SENDTOSAM,
335                                         "winbind_SendToSam",
336                                         domain, IRPC_CALL_TIMEOUT);
337 }
338
339 struct wb_irpc_lsa_LookupSids3_state {
340         struct irpc_message *msg;
341         struct lsa_LookupSids3 *req;
342 };
343
344 static void wb_irpc_lsa_LookupSids3_done(struct tevent_req *subreq);
345
346 static NTSTATUS wb_irpc_lsa_LookupSids3_call(struct irpc_message *msg,
347                                              struct lsa_LookupSids3 *req)
348 {
349         struct wb_irpc_lsa_LookupSids3_state *state = NULL;
350         struct tevent_req *subreq = NULL;
351         struct dom_sid *sids = NULL;
352         uint32_t i;
353
354         state = talloc_zero(msg, struct wb_irpc_lsa_LookupSids3_state);
355         if (state == NULL) {
356                 return NT_STATUS_NO_MEMORY;
357         }
358
359         state->msg = msg;
360         state->req = req;
361
362         state->req->out.domains = talloc_zero(state->msg,
363                                         struct lsa_RefDomainList *);
364         if (state->req->out.domains == NULL) {
365                 return NT_STATUS_NO_MEMORY;
366         }
367         state->req->out.names = talloc_zero(state->msg,
368                                             struct lsa_TransNameArray2);
369         if (state->req->out.names == NULL) {
370                 return NT_STATUS_NO_MEMORY;
371         }
372         state->req->out.count = talloc_zero(state->msg, uint32_t);
373         if (state->req->out.count == NULL) {
374                 return NT_STATUS_NO_MEMORY;
375         }
376
377         state->req->out.names->names = talloc_zero_array(state->msg,
378                                                 struct lsa_TranslatedName2,
379                                                 req->in.sids->num_sids);
380         if (state->req->out.names->names == NULL) {
381                 return NT_STATUS_NO_MEMORY;
382         }
383
384         sids = talloc_zero_array(state, struct dom_sid,
385                                  req->in.sids->num_sids);
386         if (sids == NULL) {
387                 return NT_STATUS_NO_MEMORY;
388         }
389
390         for (i = 0; i < req->in.sids->num_sids; i++) {
391                 if (req->in.sids->sids[i].sid == NULL) {
392                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
393                 }
394
395                 sids[i] = *req->in.sids->sids[i].sid;
396         }
397
398         subreq = wb_lookupsids_send(msg,
399                                     server_event_context(),
400                                     sids, req->in.sids->num_sids);
401         if (subreq == NULL) {
402                 return NT_STATUS_NO_MEMORY;
403         }
404         tevent_req_set_callback(subreq, wb_irpc_lsa_LookupSids3_done, state);
405         msg->defer_reply = true;
406
407         return NT_STATUS_OK;
408 }
409
410 static void wb_irpc_lsa_LookupSids3_done(struct tevent_req *subreq)
411 {
412         struct wb_irpc_lsa_LookupSids3_state *state =
413                 tevent_req_callback_data(subreq,
414                 struct wb_irpc_lsa_LookupSids3_state);
415         struct lsa_RefDomainList *domains = NULL;
416         struct lsa_TransNameArray *names = NULL;
417         NTSTATUS status;
418         uint32_t i;
419
420         status = wb_lookupsids_recv(subreq, state->msg,
421                                     &domains, &names);
422         TALLOC_FREE(subreq);
423         if (!NT_STATUS_IS_OK(status)) {
424                 DEBUG(0,("RPC callback failed for %s - %s\n",
425                          __func__, nt_errstr(status)));
426                 irpc_send_reply(state->msg, status);
427                 return;
428         }
429
430         if (names->count > state->req->in.sids->num_sids) {
431                 status = NT_STATUS_INTERNAL_ERROR;
432                 DEBUG(0,("RPC callback failed for %s - %s\n",
433                          __func__, nt_errstr(status)));
434                 irpc_send_reply(state->msg, status);
435                 return;
436         }
437
438         *state->req->out.domains = domains;
439         for (i = 0; i < names->count; i++) {
440                 struct lsa_TranslatedName2 *n2 =
441                         &state->req->out.names->names[i];
442
443                 n2->sid_type = names->names[i].sid_type;
444                 n2->name = names->names[i].name;
445                 n2->sid_index = names->names[i].sid_index;
446                 n2->unknown = 0;
447
448                 if (n2->sid_type != SID_NAME_UNKNOWN) {
449                         (*state->req->out.count)++;
450                 }
451         }
452         state->req->out.names->count = names->count;
453
454         if (*state->req->out.count == 0) {
455                 state->req->out.result = NT_STATUS_NONE_MAPPED;
456         } else if (*state->req->out.count != names->count) {
457                 state->req->out.result = NT_STATUS_SOME_NOT_MAPPED;
458         } else {
459                 state->req->out.result = NT_STATUS_OK;
460         }
461
462         irpc_send_reply(state->msg, NT_STATUS_OK);
463         return;
464 }
465
466 struct wb_irpc_lsa_LookupNames4_name {
467         void *state;
468         uint32_t idx;
469         const char *domain;
470         char *name;
471         struct dom_sid sid;
472         enum lsa_SidType type;
473         struct dom_sid *authority_sid;
474 };
475
476 struct wb_irpc_lsa_LookupNames4_state {
477         struct irpc_message *msg;
478         struct lsa_LookupNames4 *req;
479         struct wb_irpc_lsa_LookupNames4_name *names;
480         uint32_t num_pending;
481         uint32_t num_domain_sids;
482         struct dom_sid *domain_sids;
483 };
484
485 static void wb_irpc_lsa_LookupNames4_done(struct tevent_req *subreq);
486
487 static NTSTATUS wb_irpc_lsa_LookupNames4_call(struct irpc_message *msg,
488                                               struct lsa_LookupNames4 *req)
489 {
490         struct wb_irpc_lsa_LookupNames4_state *state = NULL;
491         struct tevent_req *subreq = NULL;
492         uint32_t i;
493
494
495         state = talloc_zero(msg, struct wb_irpc_lsa_LookupNames4_state);
496         if (state == NULL) {
497                 return NT_STATUS_NO_MEMORY;
498         }
499
500         state->msg = msg;
501         state->req = req;
502
503         state->req->out.domains = talloc_zero(state->msg,
504                                         struct lsa_RefDomainList *);
505         if (state->req->out.domains == NULL) {
506                 return NT_STATUS_NO_MEMORY;
507         }
508         state->req->out.sids = talloc_zero(state->msg,
509                                            struct lsa_TransSidArray3);
510         if (state->req->out.sids == NULL) {
511                 return NT_STATUS_NO_MEMORY;
512         }
513         state->req->out.count = talloc_zero(state->msg, uint32_t);
514         if (state->req->out.count == NULL) {
515                 return NT_STATUS_NO_MEMORY;
516         }
517
518         state->req->out.sids->sids = talloc_zero_array(state->msg,
519                                                 struct lsa_TranslatedSid3,
520                                                 req->in.num_names);
521         if (state->req->out.sids->sids == NULL) {
522                 return NT_STATUS_NO_MEMORY;
523         }
524
525         state->names = talloc_zero_array(state,
526                                          struct wb_irpc_lsa_LookupNames4_name,
527                                          req->in.num_names);
528         if (state->names == NULL) {
529                 return NT_STATUS_NO_MEMORY;
530         }
531
532         for (i = 0; i < req->in.num_names; i++) {
533                 struct wb_irpc_lsa_LookupNames4_name *nstate =
534                         &state->names[i];
535                 char *p = NULL;
536
537                 if (req->in.names[i].string == NULL) {
538                         DBG_ERR("%s: name[%s] NT_STATUS_REQUEST_NOT_ACCEPTED.\n",
539                                 __location__, req->in.names[i].string);
540                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
541                 }
542                 nstate->state = state;
543                 nstate->idx = i;
544                 nstate->name = talloc_strdup(state->names,
545                                              req->in.names[i].string);
546                 if (nstate->name == NULL) {
547                         return NT_STATUS_NO_MEMORY;
548                 }
549                 nstate->type = SID_NAME_UNKNOWN;
550
551                 /* cope with the name being a fully qualified name */
552                 p = strchr(nstate->name, '\\');
553                 if (p != NULL) {
554                         *p = 0;
555                         nstate->domain = nstate->name;
556                         nstate->name = p+1;
557                 } else if ((p = strchr(nstate->name, '@')) != NULL) {
558                         /* upn */
559                         nstate->domain = p + 1;
560                         *p = 0;
561                 } else {
562                         /*
563                          * TODO: select the domain based on
564                          * req->in.level and req->in.client_revision
565                          *
566                          * For now we don't allow this.
567                          */
568                         DBG_ERR("%s: name[%s] NT_STATUS_REQUEST_NOT_ACCEPTED.\n",
569                                 __location__, nstate->name);
570                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
571                 }
572
573                 subreq = wb_lookupname_send(msg,
574                                             server_event_context(),
575                                             nstate->domain,
576                                             nstate->name,
577                                             LOOKUP_NAME_NO_NSS);
578                 if (subreq == NULL) {
579                         return NT_STATUS_NO_MEMORY;
580                 }
581                 tevent_req_set_callback(subreq,
582                                         wb_irpc_lsa_LookupNames4_done,
583                                         nstate);
584                 state->num_pending++;
585         }
586
587         msg->defer_reply = true;
588
589         return NT_STATUS_OK;
590 }
591
592 static void wb_irpc_lsa_LookupNames4_domains_done(struct tevent_req *subreq);
593
594 static void wb_irpc_lsa_LookupNames4_done(struct tevent_req *subreq)
595 {
596         struct wb_irpc_lsa_LookupNames4_name *nstate =
597                 (struct wb_irpc_lsa_LookupNames4_name *)
598                 tevent_req_callback_data_void(subreq);
599         struct wb_irpc_lsa_LookupNames4_state *state =
600                 talloc_get_type_abort(nstate->state,
601                 struct wb_irpc_lsa_LookupNames4_state);
602         NTSTATUS status;
603
604         SMB_ASSERT(state->num_pending > 0);
605         state->num_pending--;
606         status = wb_lookupname_recv(subreq, &nstate->sid, &nstate->type);
607         TALLOC_FREE(subreq);
608         if (!NT_STATUS_IS_OK(status)) {
609                 DEBUG(0,("RPC callback failed for %s - %s\n",
610                          __func__, nt_errstr(status)));
611                 irpc_send_reply(state->msg, status);
612                 return;
613         }
614
615         status = dom_sid_split_rid(state, &nstate->sid,
616                                    &nstate->authority_sid, NULL);
617         if (!NT_STATUS_IS_OK(status)) {
618                 DBG_ERR("dom_sid_split_rid(%s) failed - %s\n",
619                          sid_string_dbg(&nstate->sid), nt_errstr(status));
620                 irpc_send_reply(state->msg, status);
621                 return;
622         }
623
624         status = add_sid_to_array_unique(state,
625                                          nstate->authority_sid,
626                                          &state->domain_sids,
627                                          &state->num_domain_sids);
628         if (!NT_STATUS_IS_OK(status)) {
629                 DBG_ERR("add_sid_to_array_unique(%s) failed - %s\n",
630                          sid_string_dbg(nstate->authority_sid), nt_errstr(status));
631                 irpc_send_reply(state->msg, status);
632                 return;
633         }
634
635         if (state->num_pending > 0) {
636                 /*
637                  * wait for more...
638                  */
639                 return;
640         }
641
642         /*
643          * Now resolve all domains back to a name
644          * to get a good lsa_RefDomainList
645          */
646         subreq = wb_lookupsids_send(state,
647                                     server_event_context(),
648                                     state->domain_sids,
649                                     state->num_domain_sids);
650         if (subreq == NULL) {
651                 status = NT_STATUS_NO_MEMORY;
652                 DBG_ERR("wb_lookupsids_send - %s\n",
653                         nt_errstr(status));
654                 irpc_send_reply(state->msg, status);
655                 return;
656         }
657         tevent_req_set_callback(subreq,
658                                 wb_irpc_lsa_LookupNames4_domains_done,
659                                 state);
660
661         return;
662 }
663
664 static void wb_irpc_lsa_LookupNames4_domains_done(struct tevent_req *subreq)
665 {
666         struct wb_irpc_lsa_LookupNames4_state *state =
667                 tevent_req_callback_data(subreq,
668                 struct wb_irpc_lsa_LookupNames4_state);
669         struct lsa_RefDomainList *domains = NULL;
670         struct lsa_TransNameArray *names = NULL;
671         NTSTATUS status;
672         uint32_t i;
673
674         status = wb_lookupsids_recv(subreq, state->msg,
675                                     &domains, &names);
676         TALLOC_FREE(subreq);
677         if (!NT_STATUS_IS_OK(status)) {
678                 DEBUG(0,("RPC callback failed for %s - %s\n",
679                          __func__, nt_errstr(status)));
680                 irpc_send_reply(state->msg, status);
681                 return;
682         }
683
684         *state->req->out.domains = domains;
685         for (i = 0; i < state->req->in.num_names; i++) {
686                 struct wb_irpc_lsa_LookupNames4_name *nstate =
687                         &state->names[i];
688                 struct lsa_TranslatedSid3 *s3 =
689                         &state->req->out.sids->sids[i];
690                 uint32_t di;
691
692                 s3->sid_type = nstate->type;
693                 if (s3->sid_type != SID_NAME_UNKNOWN) {
694                         s3->sid = &nstate->sid;
695                 } else {
696                         s3->sid = NULL;
697                 }
698                 s3->sid_index = UINT32_MAX;
699                 for (di = 0; di < domains->count; di++) {
700                         bool match;
701
702                         if (domains->domains[di].sid == NULL) {
703                                 continue;
704                         }
705
706                         match = dom_sid_equal(nstate->authority_sid,
707                                               domains->domains[di].sid);
708                         if (match) {
709                                 s3->sid_index = di;
710                                 break;
711                         }
712                 }
713                 if (s3->sid_type != SID_NAME_UNKNOWN) {
714                         (*state->req->out.count)++;
715                 }
716         }
717         state->req->out.sids->count = state->req->in.num_names;
718
719         if (*state->req->out.count == 0) {
720                 state->req->out.result = NT_STATUS_NONE_MAPPED;
721         } else if (*state->req->out.count != state->req->in.num_names) {
722                 state->req->out.result = NT_STATUS_SOME_NOT_MAPPED;
723         } else {
724                 state->req->out.result = NT_STATUS_OK;
725         }
726
727         irpc_send_reply(state->msg, NT_STATUS_OK);
728         return;
729 }
730
731 struct wb_irpc_GetDCName_state {
732         struct irpc_message *msg;
733         struct wbint_DsGetDcName *req;
734 };
735
736 static void wb_irpc_GetDCName_done(struct tevent_req *subreq);
737
738 static NTSTATUS wb_irpc_GetDCName(struct irpc_message *msg,
739                                   struct wbint_DsGetDcName *req)
740 {
741
742         struct tevent_req *subreq = NULL;
743         struct wb_irpc_GetDCName_state *state = NULL;
744
745         state = talloc_zero(msg, struct wb_irpc_GetDCName_state);
746         if (state == NULL) {
747                 return NT_STATUS_NO_MEMORY;
748         }
749
750         state->msg = msg;
751         state->req = req;
752
753         subreq = wb_dsgetdcname_send(msg,
754                                      server_event_context(),
755                                      req->in.domain_name,
756                                      req->in.domain_guid,
757                                      req->in.site_name,
758                                      req->in.flags);
759         if (subreq == NULL) {
760                 return NT_STATUS_NO_MEMORY;
761         }
762
763         tevent_req_set_callback(subreq,
764                                 wb_irpc_GetDCName_done,
765                                 state);
766
767         msg->defer_reply = true;
768
769         return NT_STATUS_OK;
770 }
771
772 static void wb_irpc_GetDCName_done(struct tevent_req *subreq)
773 {
774         struct wb_irpc_GetDCName_state *state = tevent_req_callback_data(
775                 subreq, struct wb_irpc_GetDCName_state);
776         NTSTATUS status;
777
778         status = wb_dsgetdcname_recv(subreq, state->msg,
779                                      state->req->out.dc_info);
780         TALLOC_FREE(subreq);
781         if (!NT_STATUS_IS_OK(status)) {
782                 DBG_INFO("RPC callback failed for %s - %s\n", "DSGETDCNAME",
783                          nt_errstr(status));
784         }
785
786         state->req->out.result = status;
787
788         irpc_send_reply(state->msg, NT_STATUS_OK);
789 }
790
791 NTSTATUS wb_irpc_register(void)
792 {
793         NTSTATUS status;
794
795         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_DSRUPDATEREADONLYSERVERDNSRECORDS,
796                                wb_irpc_DsrUpdateReadOnlyServerDnsRecords, NULL);
797         if (!NT_STATUS_IS_OK(status)) {
798                 return status;
799         }
800         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SAMLOGON,
801                                wb_irpc_SamLogon, NULL);
802         if (!NT_STATUS_IS_OK(status)) {
803                 return status;
804         }
805         status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
806                                WINBIND_LOGONCONTROL,
807                                wb_irpc_LogonControl, NULL);
808         if (!NT_STATUS_IS_OK(status)) {
809                 return status;
810         }
811         status = IRPC_REGISTER(winbind_imessaging_context(), winbind,
812                                WINBIND_GETFORESTTRUSTINFORMATION,
813                                wb_irpc_GetForestTrustInformation, NULL);
814         if (!NT_STATUS_IS_OK(status)) {
815                 return status;
816         }
817         status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SENDTOSAM,
818                                wb_irpc_SendToSam, NULL);
819         if (!NT_STATUS_IS_OK(status)) {
820                 return status;
821         }
822         status = IRPC_REGISTER(winbind_imessaging_context(),
823                                lsarpc, LSA_LOOKUPSIDS3,
824                                wb_irpc_lsa_LookupSids3_call, NULL);
825         if (!NT_STATUS_IS_OK(status)) {
826                 return status;
827         }
828         status = IRPC_REGISTER(winbind_imessaging_context(),
829                                lsarpc, LSA_LOOKUPNAMES4,
830                                wb_irpc_lsa_LookupNames4_call, NULL);
831         if (!NT_STATUS_IS_OK(status)) {
832                 return status;
833         }
834         status = IRPC_REGISTER(winbind_imessaging_context(),
835                                winbind, WBINT_DSGETDCNAME,
836                                wb_irpc_GetDCName, NULL);
837         if (!NT_STATUS_IS_OK(status)) {
838                 return status;
839         }
840
841         return NT_STATUS_OK;
842 }