r11528: Separate finding dcs from initializing a domain. Makes it easier to possibly
[kai/samba.git] / source4 / winbind / wb_async_helpers.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Volker Lendecke 2005
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 /*
21   a composite API for finding a DC and its name
22 */
23
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26 #include "libcli/smb_composite/smb_composite.h"
27 #include "winbind/wb_async_helpers.h"
28 #include "winbind/wb_server.h"
29 #include "smbd/service_stream.h"
30
31 #include "librpc/gen_ndr/nbt.h"
32 #include "librpc/gen_ndr/samr.h"
33 #include "lib/messaging/irpc.h"
34 #include "librpc/gen_ndr/irpc.h"
35 #include "librpc/gen_ndr/ndr_irpc.h"
36 #include "libcli/raw/libcliraw.h"
37 #include "librpc/gen_ndr/ndr_netlogon.h"
38 #include "librpc/gen_ndr/ndr_lsa.h"
39 #include "libcli/auth/credentials.h"
40
41 struct finddcs_state {
42         struct composite_context *ctx;
43         struct messaging_context *msg_ctx;
44
45         const char *domain_name;
46         const struct dom_sid *domain_sid;
47
48         struct nbtd_getdcname r;
49
50         int num_dcs;
51         struct nbt_dc_name *dcs;
52 };
53
54 static void finddcs_resolve(struct composite_context *ctx);
55 static void finddcs_getdc(struct irpc_request *ireq);
56
57 struct composite_context *wb_finddcs_send(TALLOC_CTX *mem_ctx,
58                                           const char *domain_name,
59                                           const struct dom_sid *domain_sid,
60                                           struct event_context *event_ctx,
61                                           struct messaging_context *msg_ctx)
62 {
63         struct composite_context *result, *ctx;
64         struct finddcs_state *state;
65         struct nbt_name name;
66
67         result = talloc(mem_ctx, struct composite_context);
68         if (result == NULL) goto failed;
69         result->state = COMPOSITE_STATE_IN_PROGRESS;
70         result->async.fn = NULL;
71         result->event_ctx = event_ctx;
72
73         state = talloc(result, struct finddcs_state);
74         if (state == NULL) goto failed;
75         state->ctx = result;
76         result->private_data = state;
77
78         state->domain_name = talloc_strdup(state, domain_name);
79         if (state->domain_name == NULL) goto failed;
80         state->domain_sid = dom_sid_dup(state, domain_sid);
81         if (state->domain_sid == NULL) goto failed;
82         state->msg_ctx = msg_ctx;
83
84         make_nbt_name(&name, state->domain_name, 0x1c);
85         ctx = resolve_name_send(&name, result->event_ctx,
86                                 lp_name_resolve_order());
87
88         if (ctx == NULL) goto failed;
89         ctx->async.fn = finddcs_resolve;
90         ctx->async.private_data = state;
91
92         return result;
93
94 failed:
95         talloc_free(result);
96         return NULL;
97 }
98
99 static void finddcs_resolve(struct composite_context *ctx)
100 {
101         struct finddcs_state *state =
102                 talloc_get_type(ctx->async.private_data, struct finddcs_state);
103         struct irpc_request *ireq;
104         uint32_t *nbt_servers;
105         const char *address;
106
107         state->ctx->status = resolve_name_recv(ctx, state, &address);
108         if (!composite_is_ok(state->ctx)) return;
109
110         state->num_dcs = 1;
111         state->dcs = talloc_array(state, struct nbt_dc_name, state->num_dcs);
112         if (composite_nomem(state->dcs, state->ctx)) return;
113
114         state->dcs[0].address = talloc_steal(state->dcs, address);
115
116         nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server");
117         if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) {
118                 composite_error(state->ctx, NT_STATUS_NO_LOGON_SERVERS);
119                 return;
120         }
121
122         state->r.in.domainname = state->domain_name;
123         state->r.in.ip_address = state->dcs[0].address;
124         state->r.in.my_computername = lp_netbios_name();
125         state->r.in.my_accountname = talloc_asprintf(state, "%s$",
126                                                      lp_netbios_name());
127         if (composite_nomem(state->r.in.my_accountname, state->ctx)) return;
128         state->r.in.account_control = ACB_WSTRUST;
129         state->r.in.domain_sid = dom_sid_dup(state, state->domain_sid);
130         if (composite_nomem(state->r.in.domain_sid, state->ctx)) return;
131
132         ireq = irpc_call_send(state->msg_ctx, nbt_servers[0],
133                               &dcerpc_table_irpc, DCERPC_NBTD_GETDCNAME,
134                               &state->r, state);
135         composite_continue_irpc(state->ctx, ireq, finddcs_getdc, state);
136 }
137
138 static void finddcs_getdc(struct irpc_request *ireq)
139 {
140         struct finddcs_state *state =
141                 talloc_get_type(ireq->async.private, struct finddcs_state);
142
143         state->ctx->status = irpc_call_recv(ireq);
144         talloc_free(ireq);
145         if (!composite_is_ok(state->ctx)) return;
146
147         state->dcs[0].name = talloc_steal(state->dcs, state->r.out.dcname);
148         composite_done(state->ctx);
149 }
150
151 NTSTATUS wb_finddcs_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
152                          int *num_dcs, struct nbt_dc_name **dcs)
153 {
154         NTSTATUS status = composite_wait(c);
155         if (NT_STATUS_IS_OK(status)) {
156                 struct finddcs_state *state =
157                         talloc_get_type(c->private_data, struct finddcs_state);
158                 *num_dcs = state->num_dcs;
159                 *dcs = talloc_steal(mem_ctx, state->dcs);
160         }
161         talloc_free(c);
162         return status;
163 }
164
165 NTSTATUS wb_finddcs(TALLOC_CTX *mem_ctx,
166                     const char *domain_name, const struct dom_sid *domain_sid,
167                     struct event_context *event_ctx,
168                     struct messaging_context *msg_ctx,
169                     int *num_dcs, struct nbt_dc_name **dcs)
170 {
171         struct composite_context *c = wb_finddcs_send(mem_ctx,
172                                                       domain_name, domain_sid,
173                                                       event_ctx, msg_ctx);
174         return wb_finddcs_recv(c, mem_ctx, num_dcs, dcs);
175 }
176
177 struct get_schannel_creds_state {
178         struct composite_context *ctx;
179         struct cli_credentials *wks_creds;
180         struct dcerpc_pipe *p;
181         struct netr_ServerReqChallenge r;
182
183         struct creds_CredentialState *creds_state;
184         struct netr_Credential netr_cred;
185         uint32_t negotiate_flags;
186         struct netr_ServerAuthenticate2 a;
187 };
188
189 static void get_schannel_creds_recv_auth(struct rpc_request *req);
190 static void get_schannel_creds_recv_chal(struct rpc_request *req);
191 static void get_schannel_creds_recv_pipe(struct composite_context *ctx);
192
193 struct composite_context *wb_get_schannel_creds_send(TALLOC_CTX *mem_ctx,
194                                                      struct cli_credentials *wks_creds,
195                                                      struct smbcli_tree *tree,
196                                                      struct event_context *ev)
197 {
198         struct composite_context *result, *ctx;
199         struct get_schannel_creds_state *state;
200
201         result = talloc(mem_ctx, struct composite_context);
202         if (result == NULL) goto failed;
203         result->state = COMPOSITE_STATE_IN_PROGRESS;
204         result->async.fn = NULL;
205         result->event_ctx = ev;
206
207         state = talloc(result, struct get_schannel_creds_state);
208         if (state == NULL) goto failed;
209         result->private_data = state;
210         state->ctx = result;
211
212         state->wks_creds = wks_creds;
213
214         state->p = dcerpc_pipe_init(state, ev);
215         if (state->p == NULL) goto failed;
216
217         ctx = dcerpc_pipe_open_smb_send(state->p->conn, tree, "\\netlogon");
218         if (ctx == NULL) goto failed;
219
220         ctx->async.fn = get_schannel_creds_recv_pipe;
221         ctx->async.private_data = state;
222         return result;
223
224  failed:
225         talloc_free(result);
226         return NULL;
227 }
228
229 static void get_schannel_creds_recv_pipe(struct composite_context *ctx)
230 {
231         struct get_schannel_creds_state *state =
232                 talloc_get_type(ctx->async.private_data,
233                                 struct get_schannel_creds_state);
234         struct rpc_request *req;
235
236         state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
237         if (!composite_is_ok(state->ctx)) return;
238
239         state->ctx->status = dcerpc_bind_auth_none(state->p,
240                                                    DCERPC_NETLOGON_UUID,
241                                                    DCERPC_NETLOGON_VERSION);
242         if (!composite_is_ok(state->ctx)) return;
243
244         state->r.in.computer_name =
245                 cli_credentials_get_workstation(state->wks_creds);
246         state->r.in.server_name =
247                 talloc_asprintf(state, "\\\\%s",
248                                 dcerpc_server_name(state->p));
249         if (composite_nomem(state->r.in.server_name, state->ctx)) return;
250
251         state->r.in.credentials = talloc(state, struct netr_Credential);
252         if (composite_nomem(state->r.in.credentials, state->ctx)) return;
253
254         state->r.out.credentials = talloc(state, struct netr_Credential);
255         if (composite_nomem(state->r.out.credentials, state->ctx)) return;
256
257         generate_random_buffer(state->r.in.credentials->data,
258                                sizeof(state->r.in.credentials->data));
259
260         req = dcerpc_netr_ServerReqChallenge_send(state->p, state, &state->r);
261         composite_continue_rpc(state->ctx, req,
262                                get_schannel_creds_recv_chal, state);
263 }
264
265 static void get_schannel_creds_recv_chal(struct rpc_request *req)
266 {
267         struct get_schannel_creds_state *state =
268                 talloc_get_type(req->async.private,
269                                 struct get_schannel_creds_state);
270         const struct samr_Password *mach_pwd;
271
272         state->ctx->status = dcerpc_ndr_request_recv(req);
273         if (!composite_is_ok(state->ctx)) return;
274         state->ctx->status = state->r.out.result;
275         if (!composite_is_ok(state->ctx)) return;
276
277         state->creds_state = talloc(state, struct creds_CredentialState);
278         if (composite_nomem(state->creds_state, state->ctx)) return;
279
280         mach_pwd = cli_credentials_get_nt_hash(state->wks_creds, state);
281         if (composite_nomem(mach_pwd, state->ctx)) return;
282
283         state->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
284
285         creds_client_init(state->creds_state, state->r.in.credentials,
286                           state->r.out.credentials, mach_pwd,
287                           &state->netr_cred, state->negotiate_flags);
288
289         state->a.in.server_name =
290                 talloc_reference(state, state->r.in.server_name);
291         state->a.in.account_name =
292                 cli_credentials_get_username(state->wks_creds);
293         state->a.in.secure_channel_type =
294                 cli_credentials_get_secure_channel_type(state->wks_creds);
295         state->a.in.computer_name =
296                 cli_credentials_get_workstation(state->wks_creds);
297         state->a.in.negotiate_flags = &state->negotiate_flags;
298         state->a.out.negotiate_flags = &state->negotiate_flags;
299         state->a.in.credentials = &state->netr_cred;
300         state->a.out.credentials = &state->netr_cred;
301
302         req = dcerpc_netr_ServerAuthenticate2_send(state->p, state, &state->a);
303         composite_continue_rpc(state->ctx, req,
304                                get_schannel_creds_recv_auth, state);
305 }
306
307 static void get_schannel_creds_recv_auth(struct rpc_request *req)
308 {
309         struct get_schannel_creds_state *state =
310                 talloc_get_type(req->async.private,
311                                 struct get_schannel_creds_state);
312
313         state->ctx->status = dcerpc_ndr_request_recv(req);
314         if (!NT_STATUS_IS_OK(state->ctx->status)) goto done;
315         state->ctx->status = state->a.out.result;
316         if (!NT_STATUS_IS_OK(state->ctx->status)) goto done;
317
318         if (!creds_client_check(state->creds_state,
319                                 state->a.out.credentials)) {
320                 DEBUG(5, ("Server got us invalid creds\n"));
321                 state->ctx->status = NT_STATUS_UNSUCCESSFUL;
322                 goto done;
323         }
324
325         cli_credentials_set_netlogon_creds(state->wks_creds,
326                                            state->creds_state);
327
328         state->ctx->state = COMPOSITE_STATE_DONE;
329
330  done:
331         if (!NT_STATUS_IS_OK(state->ctx->status)) {
332                 state->ctx->state = COMPOSITE_STATE_ERROR;
333         }
334         if ((state->ctx->state >= COMPOSITE_STATE_DONE) &&
335             (state->ctx->async.fn != NULL)) {
336                 state->ctx->async.fn(state->ctx);
337         }
338 }
339
340 NTSTATUS wb_get_schannel_creds_recv(struct composite_context *c,
341                                     TALLOC_CTX *mem_ctx,
342                                     struct dcerpc_pipe **netlogon_pipe)
343 {
344         NTSTATUS status = composite_wait(c);
345         if (NT_STATUS_IS_OK(status)) {
346                 struct get_schannel_creds_state *state =
347                         talloc_get_type(c->private_data,
348                                         struct get_schannel_creds_state);
349                 *netlogon_pipe = talloc_steal(mem_ctx, state->p);
350         }
351         talloc_free(c);
352         return status;
353 }
354
355 NTSTATUS wb_get_schannel_creds(TALLOC_CTX *mem_ctx,
356                                struct cli_credentials *wks_creds,
357                                struct smbcli_tree *tree,
358                                struct event_context *event_ctx,
359                                struct dcerpc_pipe **netlogon_pipe)
360 {
361         struct composite_context *c =
362                 wb_get_schannel_creds_send(mem_ctx, wks_creds, tree,
363                                            event_ctx);
364         return wb_get_schannel_creds_recv(c, mem_ctx, netlogon_pipe);
365 }
366
367 struct lsa_lookupsids_state {
368         struct composite_context *ctx;
369         int num_sids;
370         struct lsa_LookupSids r;
371         struct lsa_SidArray sids;
372         struct lsa_TransNameArray names;
373         uint32_t count;
374         struct wb_sid_object **result;
375 };
376
377 static void lsa_lookupsids_recv_names(struct rpc_request *req);
378
379 struct composite_context *wb_lsa_lookupsids_send(TALLOC_CTX *mem_ctx,
380                                                  struct dcerpc_pipe *lsa_pipe,
381                                                  struct policy_handle *handle,
382                                                  int num_sids,
383                                                  const struct dom_sid **sids)
384 {
385         struct composite_context *result;
386         struct rpc_request *req;
387         struct lsa_lookupsids_state *state;
388         int i;
389
390         result = talloc(mem_ctx, struct composite_context);
391         if (result == NULL) goto failed;
392         result->state = COMPOSITE_STATE_IN_PROGRESS;
393         result->async.fn = NULL;
394         result->event_ctx = lsa_pipe->conn->event_ctx;
395
396         state = talloc(result, struct lsa_lookupsids_state);
397         if (state == NULL) goto failed;
398         result->private_data = state;
399         state->ctx = result;
400
401         state->sids.num_sids = num_sids;
402         state->sids.sids = talloc_array(state, struct lsa_SidPtr, num_sids);
403         if (state->sids.sids == NULL) goto failed;
404
405         for (i=0; i<num_sids; i++) {
406                 state->sids.sids[i].sid = dom_sid_dup(state->sids.sids,
407                                                       sids[i]);
408                 if (state->sids.sids[i].sid == NULL) goto failed;
409         }
410
411         state->count = 0;
412         state->num_sids = num_sids;
413         state->names.count = 0;
414         state->names.names = NULL;
415
416         state->r.in.handle = handle;
417         state->r.in.sids = &state->sids;
418         state->r.in.names = &state->names;
419         state->r.in.level = 1;
420         state->r.in.count = &state->count;
421         state->r.out.names = &state->names;
422         state->r.out.count = &state->count;
423
424         req = dcerpc_lsa_LookupSids_send(lsa_pipe, state, &state->r);
425         if (req == NULL) goto failed;
426
427         req->async.callback = lsa_lookupsids_recv_names;
428         req->async.private = state;
429         return result;
430
431  failed:
432         talloc_free(result);
433         return NULL;
434 }
435
436 static void lsa_lookupsids_recv_names(struct rpc_request *req)
437 {
438         struct lsa_lookupsids_state *state =
439                 talloc_get_type(req->async.private,
440                                 struct lsa_lookupsids_state);
441         int i;
442
443         state->ctx->status = dcerpc_ndr_request_recv(req);
444         if (!composite_is_ok(state->ctx)) return;
445         state->ctx->status = state->r.out.result;
446         if (!NT_STATUS_IS_OK(state->ctx->status) &&
447             !NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
448                 composite_error(state->ctx, state->ctx->status);
449                 return;
450         }
451
452         state->result = talloc_array(state, struct wb_sid_object *,
453                                      state->num_sids);
454         if (composite_nomem(state->result, state->ctx)) return;
455
456         for (i=0; i<state->num_sids; i++) {
457                 struct lsa_TranslatedName *name =
458                         &state->r.out.names->names[i];
459                 struct lsa_TrustInformation *dom;
460
461                 state->result[i] = talloc_zero(state->result,
462                                                struct wb_sid_object);
463                 if (composite_nomem(state->result[i], state->ctx)) return;
464
465                 state->result[i]->type = name->sid_type;
466                 if (state->result[i]->type == SID_NAME_UNKNOWN) {
467                         continue;
468                 }
469
470                 if (name->sid_index >= state->r.out.domains->count) {
471                         composite_error(state->ctx,
472                                         NT_STATUS_INVALID_PARAMETER);
473                         return;
474                 }
475
476                 dom = &state->r.out.domains->domains[name->sid_index];
477                 state->result[i]->domain = talloc_reference(state->result[i],
478                                                             dom->name.string);
479                 if ((name->sid_type == SID_NAME_DOMAIN) ||
480                     (name->name.string == NULL)) {
481                         state->result[i]->name =
482                                 talloc_strdup(state->result[i], "");
483                 } else {
484                         state->result[i]->name =
485                                 talloc_steal(state->result[i],
486                                              name->name.string);
487                 }
488
489                 if (composite_nomem(state->result[i]->name, state->ctx)) {
490                         return;
491                 }
492         }
493
494         composite_done(state->ctx);
495 }
496
497 NTSTATUS wb_lsa_lookupsids_recv(struct composite_context *c,
498                                 TALLOC_CTX *mem_ctx,
499                                 struct wb_sid_object ***names)
500 {
501         NTSTATUS status = composite_wait(c);
502         if (NT_STATUS_IS_OK(status)) {
503                 struct lsa_lookupsids_state *state =
504                         talloc_get_type(c->private_data,
505                                         struct lsa_lookupsids_state);
506                 *names = talloc_steal(mem_ctx, state->result);
507         }
508         talloc_free(c);
509         return status;
510 }
511
512 NTSTATUS wb_lsa_lookupsids(TALLOC_CTX *mem_ctx,
513                            struct dcerpc_pipe *lsa_pipe,
514                            struct policy_handle *handle,
515                            int num_sids, const struct dom_sid **sids,
516                            struct wb_sid_object ***names)
517 {
518         struct composite_context *c =
519                 wb_lsa_lookupsids_send(mem_ctx, lsa_pipe, handle,
520                                        num_sids, sids);
521         return wb_lsa_lookupnames_recv(c, mem_ctx, names);
522 }
523
524                            
525
526 struct lsa_lookupnames_state {
527         struct composite_context *ctx;
528         uint32_t num_names;
529         struct lsa_LookupNames r;
530         struct lsa_TransSidArray sids;
531         uint32_t count;
532         struct wb_sid_object **result;
533 };
534
535 static void lsa_lookupnames_recv_sids(struct rpc_request *req);
536
537 struct composite_context *wb_lsa_lookupnames_send(TALLOC_CTX *mem_ctx,
538                                                   struct dcerpc_pipe *lsa_pipe,
539                                                   struct policy_handle *handle,
540                                                   int num_names,
541                                                   const char **names)
542 {
543         struct composite_context *result;
544         struct rpc_request *req;
545         struct lsa_lookupnames_state *state;
546
547         struct lsa_String *lsa_names;
548         int i;
549
550         result = talloc(mem_ctx, struct composite_context);
551         if (result == NULL) goto failed;
552         result->state = COMPOSITE_STATE_IN_PROGRESS;
553         result->async.fn = NULL;
554         result->event_ctx = lsa_pipe->conn->event_ctx;
555
556         state = talloc(result, struct lsa_lookupnames_state);
557         if (state == NULL) goto failed;
558         result->private_data = state;
559         state->ctx = result;
560
561         state->sids.count = 0;
562         state->sids.sids = NULL;
563         state->num_names = num_names;
564         state->count = 0;
565
566         lsa_names = talloc_array(state, struct lsa_String, num_names);
567         if (lsa_names == NULL) goto failed;
568
569         for (i=0; i<num_names; i++) {
570                 lsa_names[i].string = names[i];
571         }
572
573         state->r.in.handle = handle;
574         state->r.in.num_names = num_names;
575         state->r.in.names = lsa_names;
576         state->r.in.sids = &state->sids;
577         state->r.in.level = 1;
578         state->r.in.count = &state->count;
579         state->r.out.count = &state->count;
580         state->r.out.sids = &state->sids;
581
582         req = dcerpc_lsa_LookupNames_send(lsa_pipe, state, &state->r);
583         if (req == NULL) goto failed;
584
585         req->async.callback = lsa_lookupnames_recv_sids;
586         req->async.private = state;
587         return result;
588
589  failed:
590         talloc_free(result);
591         return NULL;
592 }
593
594 static void lsa_lookupnames_recv_sids(struct rpc_request *req)
595 {
596         struct lsa_lookupnames_state *state =
597                 talloc_get_type(req->async.private,
598                                 struct lsa_lookupnames_state);
599         int i;
600
601         state->ctx->status = dcerpc_ndr_request_recv(req);
602         if (!composite_is_ok(state->ctx)) return;
603         state->ctx->status = state->r.out.result;
604         if (!NT_STATUS_IS_OK(state->ctx->status) &&
605             !NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
606                 composite_error(state->ctx, state->ctx->status);
607                 return;
608         }
609
610         state->result = talloc_array(state, struct wb_sid_object *,
611                                      state->num_names);
612         if (composite_nomem(state->result, state->ctx)) return;
613
614         for (i=0; i<state->num_names; i++) {
615                 struct lsa_TranslatedSid *sid = &state->r.out.sids->sids[i];
616                 struct lsa_TrustInformation *dom;
617
618                 state->result[i] = talloc_zero(state->result,
619                                                struct wb_sid_object);
620                 if (composite_nomem(state->result[i], state->ctx)) return;
621
622                 state->result[i]->type = sid->sid_type;
623                 if (state->result[i]->type == SID_NAME_UNKNOWN) {
624                         continue;
625                 }
626
627                 if (sid->sid_index >= state->r.out.domains->count) {
628                         composite_error(state->ctx,
629                                         NT_STATUS_INVALID_PARAMETER);
630                         return;
631                 }
632
633                 dom = &state->r.out.domains->domains[sid->sid_index];
634
635                 state->result[i]->sid = dom_sid_add_rid(state->result[i],
636                                                         dom->sid, sid->rid);
637         }
638
639         composite_done(state->ctx);
640 }
641
642 NTSTATUS wb_lsa_lookupnames_recv(struct composite_context *c,
643                                  TALLOC_CTX *mem_ctx,
644                                  struct wb_sid_object ***sids)
645 {
646         NTSTATUS status = composite_wait(c);
647         if (NT_STATUS_IS_OK(status)) {
648                 struct lsa_lookupnames_state *state =
649                         talloc_get_type(c->private_data,
650                                         struct lsa_lookupnames_state);
651                 *sids = talloc_steal(mem_ctx, state->result);
652         }
653         talloc_free(c);
654         return status;
655 }
656
657 NTSTATUS wb_lsa_lookupnames(TALLOC_CTX *mem_ctx,
658                             struct dcerpc_pipe *lsa_pipe, 
659                             struct policy_handle *handle,
660                             int num_names, const char **names,
661                             struct wb_sid_object ***sids)
662 {
663         struct composite_context *c =
664                 wb_lsa_lookupnames_send(mem_ctx, lsa_pipe, handle,
665                                         num_names, names);
666         return wb_lsa_lookupnames_recv(c, mem_ctx, sids);
667 }
668
669 #if 0
670
671 struct cmd_checkmachacc_state {
672         struct composite_context *ctx;
673         struct wbsrv_call *call;
674         struct wbsrv_domain *domain;
675 };
676
677 static void cmd_checkmachacc_recv_init(struct composite_context *ctx);
678
679 struct composite_context *wb_cmd_checkmachacc_send(struct wbsrv_call *call)
680 {
681         struct composite_context *result, *ctx;
682         struct cmd_checkmachacc_state *state;
683         struct wbsrv_service *service = call->wbconn->listen_socket->service;
684
685         result = talloc(call, struct composite_context);
686         if (result == NULL) goto failed;
687         result->state = COMPOSITE_STATE_IN_PROGRESS;
688         result->async.fn = NULL;
689         result->event_ctx = call->event_ctx;
690
691         state = talloc(result, struct cmd_checkmachacc_state);
692         if (state == NULL) goto failed;
693         state->ctx = result;
694         result->private_data = state;
695         state->call = call;
696
697         state->domain = service->domains;
698
699         ctx = wb_init_domain_send(service, state->domain);
700         if (ctx == NULL) goto failed;
701         ctx->async.fn = cmd_checkmachacc_recv_init;
702         ctx->async.private_data = state;
703
704         return result;
705
706  failed:
707         talloc_free(result);
708         return NULL;
709 }
710
711 static void cmd_checkmachacc_recv_init(struct composite_context *ctx)
712 {
713         struct cmd_checkmachacc_state *state =
714                 talloc_get_type(ctx->async.private_data,
715                                 struct cmd_checkmachacc_state);
716
717         state->ctx->status = wb_init_domain_recv(ctx);
718         if (!composite_is_ok(state->ctx)) return;
719
720         composite_done(state->ctx);
721 }
722
723 NTSTATUS wb_cmd_checkmachacc_recv(struct composite_context *c)
724 {
725         NTSTATUS status = composite_wait(c);
726         talloc_free(c);
727         return status;
728 }
729
730 NTSTATUS wb_cmd_checkmachacc(struct wbsrv_call *call)
731 {
732         struct composite_context *c = wb_cmd_checkmachacc_send(call);
733         return wb_cmd_checkmachacc_recv(c);
734 }
735 #endif
736
737 struct samr_getuserdomgroups_state {
738         struct composite_context *ctx;
739         struct dcerpc_pipe *samr_pipe;
740
741         int num_rids;
742         uint32_t *rids;
743
744         struct policy_handle *user_handle;
745         struct samr_OpenUser o;
746         struct samr_GetGroupsForUser g;
747         struct samr_Close c;
748 };
749
750 static void samr_usergroups_recv_open(struct rpc_request *req);
751 static void samr_usergroups_recv_groups(struct rpc_request *req);
752 static void samr_usergroups_recv_close(struct rpc_request *req);
753
754 struct composite_context *wb_samr_userdomgroups_send(TALLOC_CTX *mem_ctx,
755                                                      struct dcerpc_pipe *samr_pipe,
756                                                      struct policy_handle *domain_handle,
757                                                      uint32_t rid)
758 {
759         struct composite_context *result;
760         struct rpc_request *req;
761         struct samr_getuserdomgroups_state *state;
762
763         result = talloc(mem_ctx, struct composite_context);
764         if (result == NULL) goto failed;
765         result->state = COMPOSITE_STATE_IN_PROGRESS;
766         result->async.fn = NULL;
767         result->event_ctx = samr_pipe->conn->event_ctx;
768
769         state = talloc(result, struct samr_getuserdomgroups_state);
770         if (state == NULL) goto failed;
771         result->private_data = state;
772         state->ctx = result;
773
774         state->samr_pipe = samr_pipe;
775
776         state->user_handle = talloc(state, struct policy_handle);
777         if (state->user_handle == NULL) goto failed;
778
779         state->o.in.domain_handle = domain_handle;
780         state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
781         state->o.in.rid = rid;
782         state->o.out.user_handle = state->user_handle;
783
784         req = dcerpc_samr_OpenUser_send(state->samr_pipe, state, &state->o);
785         if (req == NULL) goto failed;
786
787         req->async.callback = samr_usergroups_recv_open;
788         req->async.private = state;
789         return result;
790
791  failed:
792         talloc_free(result);
793         return NULL;
794 }
795                                               
796 static void samr_usergroups_recv_open(struct rpc_request *req)
797 {
798         struct samr_getuserdomgroups_state *state =
799                 talloc_get_type(req->async.private,
800                                 struct samr_getuserdomgroups_state);
801
802         state->ctx->status = dcerpc_ndr_request_recv(req);
803         if (!composite_is_ok(state->ctx)) return;
804         state->ctx->status = state->o.out.result;
805         if (!composite_is_ok(state->ctx)) return;
806
807         state->g.in.user_handle = state->user_handle;
808
809         req = dcerpc_samr_GetGroupsForUser_send(state->samr_pipe, state,
810                                                 &state->g);
811         composite_continue_rpc(state->ctx, req, samr_usergroups_recv_groups,
812                                state);
813 }
814
815 static void samr_usergroups_recv_groups(struct rpc_request *req)
816 {
817         struct samr_getuserdomgroups_state *state =
818                 talloc_get_type(req->async.private,
819                                 struct samr_getuserdomgroups_state);
820
821         state->ctx->status = dcerpc_ndr_request_recv(req);
822         if (!composite_is_ok(state->ctx)) return;
823         state->ctx->status = state->g.out.result;
824         if (!composite_is_ok(state->ctx)) return;
825
826         state->c.in.handle = state->user_handle;
827         state->c.out.handle = state->user_handle;
828
829         req = dcerpc_samr_Close_send(state->samr_pipe, state, &state->c);
830         composite_continue_rpc(state->ctx, req, samr_usergroups_recv_close,
831                                state);
832 }
833
834 static void samr_usergroups_recv_close(struct rpc_request *req)
835 {
836         struct samr_getuserdomgroups_state *state =
837                 talloc_get_type(req->async.private,
838                                 struct samr_getuserdomgroups_state);
839
840         state->ctx->status = dcerpc_ndr_request_recv(req);
841         if (!composite_is_ok(state->ctx)) return;
842         state->ctx->status = state->c.out.result;
843         if (!composite_is_ok(state->ctx)) return;
844
845         composite_done(state->ctx);
846 }
847
848 NTSTATUS wb_samr_userdomgroups_recv(struct composite_context *ctx,
849                                     TALLOC_CTX *mem_ctx,
850                                     int *num_rids, uint32_t **rids)
851 {
852         struct samr_getuserdomgroups_state *state =
853                 talloc_get_type(ctx->private_data,
854                                 struct samr_getuserdomgroups_state);
855
856         int i;
857         NTSTATUS status = composite_wait(ctx);
858         if (!NT_STATUS_IS_OK(status)) goto done;
859
860         *num_rids = state->g.out.rids->count;
861         *rids = talloc_array(mem_ctx, uint32_t, *num_rids);
862         if (*rids == NULL) {
863                 status = NT_STATUS_NO_MEMORY;
864                 goto done;
865         }
866
867         for (i=0; i<*num_rids; i++) {
868                 (*rids)[i] = state->g.out.rids->rids[i].rid;
869         }
870
871  done:
872         talloc_free(ctx);
873         return status;
874 }