f4de7d42845e0a81ee78cc4f286498f37b613623
[bbaumbach/samba-autobuild/.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 "winbind/wb_async_helpers.h"
27
28 #include "lib/messaging/irpc.h"
29 #include "librpc/gen_ndr/ndr_irpc.h"
30 #include "libcli/auth/credentials.h"
31
32 struct get_schannel_creds_state {
33         struct cli_credentials *wks_creds;
34         struct dcerpc_pipe *p;
35         struct netr_ServerReqChallenge r;
36
37         struct creds_CredentialState *creds_state;
38         struct netr_Credential netr_cred;
39         uint32_t negotiate_flags;
40         struct netr_ServerAuthenticate2 a;
41 };
42
43 static void get_schannel_creds_recv_anonbind(struct composite_context *creq);
44 static void get_schannel_creds_recv_auth(struct rpc_request *req);
45 static void get_schannel_creds_recv_chal(struct rpc_request *req);
46 static void get_schannel_creds_recv_pipe(struct composite_context *ctx);
47
48 struct composite_context *wb_get_schannel_creds_send(TALLOC_CTX *mem_ctx,
49                                                      struct cli_credentials *wks_creds,
50                                                      struct smbcli_tree *tree,
51                                                      struct event_context *ev)
52 {
53         struct composite_context *c, *creq;
54         struct get_schannel_creds_state *state;
55
56         c = talloc_zero(mem_ctx, struct composite_context);
57         if (c == NULL) return NULL;
58
59         state = talloc(c, struct get_schannel_creds_state);
60         if (state == NULL) {
61                 c->status = NT_STATUS_NO_MEMORY;
62                 goto failed;
63         }
64
65         c->state = COMPOSITE_STATE_IN_PROGRESS;
66         c->private_data = state;
67         c->event_ctx = ev;
68
69         state->wks_creds = wks_creds;
70
71         state->p = dcerpc_pipe_init(state, ev);
72         if (state->p == NULL) {
73                 c->status = NT_STATUS_NO_MEMORY;
74                 goto failed;
75         }
76
77         creq = dcerpc_pipe_open_smb_send(state->p->conn, tree, "\\netlogon");
78         if (creq == NULL) {
79                 c->status = NT_STATUS_NO_MEMORY;
80                 goto failed;
81         }
82
83         creq->async.fn = get_schannel_creds_recv_pipe;
84         creq->async.private_data = c;
85
86         return c;
87
88  failed:
89         composite_error(c, c->status);
90         return c;
91 }
92
93 static void get_schannel_creds_recv_pipe(struct composite_context *creq)
94 {
95         struct composite_context *c =
96                 talloc_get_type(creq->async.private_data,
97                                 struct composite_context);
98         struct get_schannel_creds_state *state =
99                 talloc_get_type(c->private_data,
100                                 struct get_schannel_creds_state);
101
102         c->status = dcerpc_pipe_open_smb_recv(creq);
103         if (!composite_is_ok(c)) return;
104
105         creq = dcerpc_bind_auth_none_send(state, state->p,
106                                                                           &dcerpc_table_netlogon);
107         composite_continue(c, creq, get_schannel_creds_recv_anonbind, c);
108 }
109
110 static void get_schannel_creds_recv_anonbind(struct composite_context *creq)
111 {
112         struct composite_context *c =
113                 talloc_get_type(creq->async.private_data,
114                                 struct composite_context);
115         struct get_schannel_creds_state *state =
116                 talloc_get_type(c->private_data,
117                                 struct get_schannel_creds_state);
118         struct rpc_request *req;
119
120         c->status = dcerpc_bind_auth_none_recv(creq);
121         if (!composite_is_ok(c)) return;
122
123         state->r.in.computer_name =
124                 cli_credentials_get_workstation(state->wks_creds);
125         state->r.in.server_name =
126                 talloc_asprintf(state, "\\\\%s",
127                                 dcerpc_server_name(state->p));
128         if (composite_nomem(state->r.in.server_name, c)) return;
129
130         state->r.in.credentials = talloc(state, struct netr_Credential);
131         if (composite_nomem(state->r.in.credentials, c)) return;
132
133         state->r.out.credentials = talloc(state, struct netr_Credential);
134         if (composite_nomem(state->r.out.credentials, c)) return;
135
136         generate_random_buffer(state->r.in.credentials->data,
137                                sizeof(state->r.in.credentials->data));
138
139         req = dcerpc_netr_ServerReqChallenge_send(state->p, state, &state->r);
140         composite_continue_rpc(c, req, get_schannel_creds_recv_chal, c);
141 }
142
143 static void get_schannel_creds_recv_chal(struct rpc_request *req)
144 {
145         struct composite_context *c =
146                 talloc_get_type(req->async.private,
147                                 struct composite_context);
148         struct get_schannel_creds_state *state =
149                 talloc_get_type(c->private_data,
150                                 struct get_schannel_creds_state);
151         const struct samr_Password *mach_pwd;
152
153         c->status = dcerpc_ndr_request_recv(req);
154         if (!composite_is_ok(c)) return;
155         c->status = state->r.out.result;
156         if (!composite_is_ok(c)) return;
157
158         state->creds_state = talloc(state, struct creds_CredentialState);
159         if (composite_nomem(state->creds_state, c)) return;
160
161         mach_pwd = cli_credentials_get_nt_hash(state->wks_creds, state);
162         if (composite_nomem(mach_pwd, c)) return;
163
164         state->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
165
166         creds_client_init(state->creds_state, state->r.in.credentials,
167                           state->r.out.credentials, mach_pwd,
168                           &state->netr_cred, state->negotiate_flags);
169
170         state->a.in.server_name =
171                 talloc_reference(state, state->r.in.server_name);
172         state->a.in.account_name =
173                 cli_credentials_get_username(state->wks_creds);
174         state->a.in.secure_channel_type =
175                 cli_credentials_get_secure_channel_type(state->wks_creds);
176         state->a.in.computer_name =
177                 cli_credentials_get_workstation(state->wks_creds);
178         state->a.in.negotiate_flags = &state->negotiate_flags;
179         state->a.out.negotiate_flags = &state->negotiate_flags;
180         state->a.in.credentials = &state->netr_cred;
181         state->a.out.credentials = &state->netr_cred;
182
183         req = dcerpc_netr_ServerAuthenticate2_send(state->p, state, &state->a);
184         composite_continue_rpc(c, req, get_schannel_creds_recv_auth, c);
185 }
186
187 static void get_schannel_creds_recv_auth(struct rpc_request *req)
188 {
189         struct composite_context *c =
190                 talloc_get_type(req->async.private,
191                                 struct composite_context);
192         struct get_schannel_creds_state *state =
193                 talloc_get_type(c->private_data,
194                                 struct get_schannel_creds_state);
195
196         c->status = dcerpc_ndr_request_recv(req);
197         if (!composite_is_ok(c)) return;
198         c->status = state->a.out.result;
199         if (!composite_is_ok(c)) return;
200
201         if (!creds_client_check(state->creds_state,
202                                 state->a.out.credentials)) {
203                 DEBUG(5, ("Server got us invalid creds\n"));
204                 composite_error(c, NT_STATUS_UNSUCCESSFUL);
205                 return;
206         }
207
208         cli_credentials_set_netlogon_creds(state->wks_creds,
209                                            state->creds_state);
210
211         composite_done(c);
212 }
213
214 NTSTATUS wb_get_schannel_creds_recv(struct composite_context *c,
215                                     TALLOC_CTX *mem_ctx,
216                                     struct dcerpc_pipe **netlogon_pipe)
217 {
218         NTSTATUS status = composite_wait(c);
219         if (NT_STATUS_IS_OK(status)) {
220                 struct get_schannel_creds_state *state =
221                         talloc_get_type(c->private_data,
222                                         struct get_schannel_creds_state);
223                 *netlogon_pipe = talloc_steal(mem_ctx, state->p);
224         }
225         talloc_free(c);
226         return status;
227 }
228
229 NTSTATUS wb_get_schannel_creds(TALLOC_CTX *mem_ctx,
230                                struct cli_credentials *wks_creds,
231                                struct smbcli_tree *tree,
232                                struct event_context *event_ctx,
233                                struct dcerpc_pipe **netlogon_pipe)
234 {
235         struct composite_context *c =
236                 wb_get_schannel_creds_send(mem_ctx, wks_creds, tree,
237                                            event_ctx);
238         return wb_get_schannel_creds_recv(c, mem_ctx, netlogon_pipe);
239 }
240
241 struct lsa_lookupsids_state {
242         struct composite_context *ctx;
243         int num_sids;
244         struct lsa_LookupSids r;
245         struct lsa_SidArray sids;
246         struct lsa_TransNameArray names;
247         uint32_t count;
248         struct wb_sid_object **result;
249 };
250
251 static void lsa_lookupsids_recv_names(struct rpc_request *req);
252
253 struct composite_context *wb_lsa_lookupsids_send(TALLOC_CTX *mem_ctx,
254                                                  struct dcerpc_pipe *lsa_pipe,
255                                                  struct policy_handle *handle,
256                                                  int num_sids,
257                                                  const struct dom_sid **sids)
258 {
259         struct composite_context *result;
260         struct rpc_request *req;
261         struct lsa_lookupsids_state *state;
262         int i;
263
264         result = talloc(mem_ctx, struct composite_context);
265         if (result == NULL) goto failed;
266         result->state = COMPOSITE_STATE_IN_PROGRESS;
267         result->async.fn = NULL;
268         result->event_ctx = lsa_pipe->conn->event_ctx;
269
270         state = talloc(result, struct lsa_lookupsids_state);
271         if (state == NULL) goto failed;
272         result->private_data = state;
273         state->ctx = result;
274
275         state->sids.num_sids = num_sids;
276         state->sids.sids = talloc_array(state, struct lsa_SidPtr, num_sids);
277         if (state->sids.sids == NULL) goto failed;
278
279         for (i=0; i<num_sids; i++) {
280                 state->sids.sids[i].sid = dom_sid_dup(state->sids.sids,
281                                                       sids[i]);
282                 if (state->sids.sids[i].sid == NULL) goto failed;
283         }
284
285         state->count = 0;
286         state->num_sids = num_sids;
287         state->names.count = 0;
288         state->names.names = NULL;
289
290         state->r.in.handle = handle;
291         state->r.in.sids = &state->sids;
292         state->r.in.names = &state->names;
293         state->r.in.level = 1;
294         state->r.in.count = &state->count;
295         state->r.out.names = &state->names;
296         state->r.out.count = &state->count;
297
298         req = dcerpc_lsa_LookupSids_send(lsa_pipe, state, &state->r);
299         if (req == NULL) goto failed;
300
301         req->async.callback = lsa_lookupsids_recv_names;
302         req->async.private = state;
303         return result;
304
305  failed:
306         talloc_free(result);
307         return NULL;
308 }
309
310 static void lsa_lookupsids_recv_names(struct rpc_request *req)
311 {
312         struct lsa_lookupsids_state *state =
313                 talloc_get_type(req->async.private,
314                                 struct lsa_lookupsids_state);
315         int i;
316
317         state->ctx->status = dcerpc_ndr_request_recv(req);
318         if (!composite_is_ok(state->ctx)) return;
319         state->ctx->status = state->r.out.result;
320         if (!NT_STATUS_IS_OK(state->ctx->status) &&
321             !NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
322                 composite_error(state->ctx, state->ctx->status);
323                 return;
324         }
325
326         state->result = talloc_array(state, struct wb_sid_object *,
327                                      state->num_sids);
328         if (composite_nomem(state->result, state->ctx)) return;
329
330         for (i=0; i<state->num_sids; i++) {
331                 struct lsa_TranslatedName *name =
332                         &state->r.out.names->names[i];
333                 struct lsa_TrustInformation *dom;
334
335                 state->result[i] = talloc_zero(state->result,
336                                                struct wb_sid_object);
337                 if (composite_nomem(state->result[i], state->ctx)) return;
338
339                 state->result[i]->type = name->sid_type;
340                 if (state->result[i]->type == SID_NAME_UNKNOWN) {
341                         continue;
342                 }
343
344                 if (name->sid_index >= state->r.out.domains->count) {
345                         composite_error(state->ctx,
346                                         NT_STATUS_INVALID_PARAMETER);
347                         return;
348                 }
349
350                 dom = &state->r.out.domains->domains[name->sid_index];
351                 state->result[i]->domain = talloc_reference(state->result[i],
352                                                             dom->name.string);
353                 if ((name->sid_type == SID_NAME_DOMAIN) ||
354                     (name->name.string == NULL)) {
355                         state->result[i]->name =
356                                 talloc_strdup(state->result[i], "");
357                 } else {
358                         state->result[i]->name =
359                                 talloc_steal(state->result[i],
360                                              name->name.string);
361                 }
362
363                 if (composite_nomem(state->result[i]->name, state->ctx)) {
364                         return;
365                 }
366         }
367
368         composite_done(state->ctx);
369 }
370
371 NTSTATUS wb_lsa_lookupsids_recv(struct composite_context *c,
372                                 TALLOC_CTX *mem_ctx,
373                                 struct wb_sid_object ***names)
374 {
375         NTSTATUS status = composite_wait(c);
376         if (NT_STATUS_IS_OK(status)) {
377                 struct lsa_lookupsids_state *state =
378                         talloc_get_type(c->private_data,
379                                         struct lsa_lookupsids_state);
380                 *names = talloc_steal(mem_ctx, state->result);
381         }
382         talloc_free(c);
383         return status;
384 }
385
386 NTSTATUS wb_lsa_lookupsids(TALLOC_CTX *mem_ctx,
387                            struct dcerpc_pipe *lsa_pipe,
388                            struct policy_handle *handle,
389                            int num_sids, const struct dom_sid **sids,
390                            struct wb_sid_object ***names)
391 {
392         struct composite_context *c =
393                 wb_lsa_lookupsids_send(mem_ctx, lsa_pipe, handle,
394                                        num_sids, sids);
395         return wb_lsa_lookupnames_recv(c, mem_ctx, names);
396 }
397
398                            
399
400 struct lsa_lookupnames_state {
401         struct composite_context *ctx;
402         uint32_t num_names;
403         struct lsa_LookupNames r;
404         struct lsa_TransSidArray sids;
405         uint32_t count;
406         struct wb_sid_object **result;
407 };
408
409 static void lsa_lookupnames_recv_sids(struct rpc_request *req);
410
411 struct composite_context *wb_lsa_lookupnames_send(TALLOC_CTX *mem_ctx,
412                                                   struct dcerpc_pipe *lsa_pipe,
413                                                   struct policy_handle *handle,
414                                                   int num_names,
415                                                   const char **names)
416 {
417         struct composite_context *result;
418         struct rpc_request *req;
419         struct lsa_lookupnames_state *state;
420
421         struct lsa_String *lsa_names;
422         int i;
423
424         result = talloc(mem_ctx, struct composite_context);
425         if (result == NULL) goto failed;
426         result->state = COMPOSITE_STATE_IN_PROGRESS;
427         result->async.fn = NULL;
428         result->event_ctx = lsa_pipe->conn->event_ctx;
429
430         state = talloc(result, struct lsa_lookupnames_state);
431         if (state == NULL) goto failed;
432         result->private_data = state;
433         state->ctx = result;
434
435         state->sids.count = 0;
436         state->sids.sids = NULL;
437         state->num_names = num_names;
438         state->count = 0;
439
440         lsa_names = talloc_array(state, struct lsa_String, num_names);
441         if (lsa_names == NULL) goto failed;
442
443         for (i=0; i<num_names; i++) {
444                 lsa_names[i].string = names[i];
445         }
446
447         state->r.in.handle = handle;
448         state->r.in.num_names = num_names;
449         state->r.in.names = lsa_names;
450         state->r.in.sids = &state->sids;
451         state->r.in.level = 1;
452         state->r.in.count = &state->count;
453         state->r.out.count = &state->count;
454         state->r.out.sids = &state->sids;
455
456         req = dcerpc_lsa_LookupNames_send(lsa_pipe, state, &state->r);
457         if (req == NULL) goto failed;
458
459         req->async.callback = lsa_lookupnames_recv_sids;
460         req->async.private = state;
461         return result;
462
463  failed:
464         talloc_free(result);
465         return NULL;
466 }
467
468 static void lsa_lookupnames_recv_sids(struct rpc_request *req)
469 {
470         struct lsa_lookupnames_state *state =
471                 talloc_get_type(req->async.private,
472                                 struct lsa_lookupnames_state);
473         int i;
474
475         state->ctx->status = dcerpc_ndr_request_recv(req);
476         if (!composite_is_ok(state->ctx)) return;
477         state->ctx->status = state->r.out.result;
478         if (!NT_STATUS_IS_OK(state->ctx->status) &&
479             !NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
480                 composite_error(state->ctx, state->ctx->status);
481                 return;
482         }
483
484         state->result = talloc_array(state, struct wb_sid_object *,
485                                      state->num_names);
486         if (composite_nomem(state->result, state->ctx)) return;
487
488         for (i=0; i<state->num_names; i++) {
489                 struct lsa_TranslatedSid *sid = &state->r.out.sids->sids[i];
490                 struct lsa_TrustInformation *dom;
491
492                 state->result[i] = talloc_zero(state->result,
493                                                struct wb_sid_object);
494                 if (composite_nomem(state->result[i], state->ctx)) return;
495
496                 state->result[i]->type = sid->sid_type;
497                 if (state->result[i]->type == SID_NAME_UNKNOWN) {
498                         continue;
499                 }
500
501                 if (sid->sid_index >= state->r.out.domains->count) {
502                         composite_error(state->ctx,
503                                         NT_STATUS_INVALID_PARAMETER);
504                         return;
505                 }
506
507                 dom = &state->r.out.domains->domains[sid->sid_index];
508
509                 state->result[i]->sid = dom_sid_add_rid(state->result[i],
510                                                         dom->sid, sid->rid);
511         }
512
513         composite_done(state->ctx);
514 }
515
516 NTSTATUS wb_lsa_lookupnames_recv(struct composite_context *c,
517                                  TALLOC_CTX *mem_ctx,
518                                  struct wb_sid_object ***sids)
519 {
520         NTSTATUS status = composite_wait(c);
521         if (NT_STATUS_IS_OK(status)) {
522                 struct lsa_lookupnames_state *state =
523                         talloc_get_type(c->private_data,
524                                         struct lsa_lookupnames_state);
525                 *sids = talloc_steal(mem_ctx, state->result);
526         }
527         talloc_free(c);
528         return status;
529 }
530
531 NTSTATUS wb_lsa_lookupnames(TALLOC_CTX *mem_ctx,
532                             struct dcerpc_pipe *lsa_pipe, 
533                             struct policy_handle *handle,
534                             int num_names, const char **names,
535                             struct wb_sid_object ***sids)
536 {
537         struct composite_context *c =
538                 wb_lsa_lookupnames_send(mem_ctx, lsa_pipe, handle,
539                                         num_names, names);
540         return wb_lsa_lookupnames_recv(c, mem_ctx, sids);
541 }
542
543 #if 0
544
545 struct cmd_checkmachacc_state {
546         struct composite_context *ctx;
547         struct wbsrv_call *call;
548         struct wbsrv_domain *domain;
549 };
550
551 static void cmd_checkmachacc_recv_init(struct composite_context *ctx);
552
553 struct composite_context *wb_cmd_checkmachacc_send(struct wbsrv_call *call)
554 {
555         struct composite_context *result, *ctx;
556         struct cmd_checkmachacc_state *state;
557         struct wbsrv_service *service = call->wbconn->listen_socket->service;
558
559         result = talloc(call, struct composite_context);
560         if (result == NULL) goto failed;
561         result->state = COMPOSITE_STATE_IN_PROGRESS;
562         result->async.fn = NULL;
563         result->event_ctx = call->event_ctx;
564
565         state = talloc(result, struct cmd_checkmachacc_state);
566         if (state == NULL) goto failed;
567         state->ctx = result;
568         result->private_data = state;
569         state->call = call;
570
571         state->domain = service->domains;
572
573         ctx = wb_init_domain_send(service, state->domain);
574         if (ctx == NULL) goto failed;
575         ctx->async.fn = cmd_checkmachacc_recv_init;
576         ctx->async.private_data = state;
577
578         return result;
579
580  failed:
581         talloc_free(result);
582         return NULL;
583 }
584
585 static void cmd_checkmachacc_recv_init(struct composite_context *ctx)
586 {
587         struct cmd_checkmachacc_state *state =
588                 talloc_get_type(ctx->async.private_data,
589                                 struct cmd_checkmachacc_state);
590
591         state->ctx->status = wb_init_domain_recv(ctx);
592         if (!composite_is_ok(state->ctx)) return;
593
594         composite_done(state->ctx);
595 }
596
597 NTSTATUS wb_cmd_checkmachacc_recv(struct composite_context *c)
598 {
599         NTSTATUS status = composite_wait(c);
600         talloc_free(c);
601         return status;
602 }
603
604 NTSTATUS wb_cmd_checkmachacc(struct wbsrv_call *call)
605 {
606         struct composite_context *c = wb_cmd_checkmachacc_send(call);
607         return wb_cmd_checkmachacc_recv(c);
608 }
609 #endif
610
611 struct samr_getuserdomgroups_state {
612         struct composite_context *ctx;
613         struct dcerpc_pipe *samr_pipe;
614
615         int num_rids;
616         uint32_t *rids;
617
618         struct policy_handle *user_handle;
619         struct samr_OpenUser o;
620         struct samr_GetGroupsForUser g;
621         struct samr_Close c;
622 };
623
624 static void samr_usergroups_recv_open(struct rpc_request *req);
625 static void samr_usergroups_recv_groups(struct rpc_request *req);
626 static void samr_usergroups_recv_close(struct rpc_request *req);
627
628 struct composite_context *wb_samr_userdomgroups_send(TALLOC_CTX *mem_ctx,
629                                                      struct dcerpc_pipe *samr_pipe,
630                                                      struct policy_handle *domain_handle,
631                                                      uint32_t rid)
632 {
633         struct composite_context *result;
634         struct rpc_request *req;
635         struct samr_getuserdomgroups_state *state;
636
637         result = talloc(mem_ctx, struct composite_context);
638         if (result == NULL) goto failed;
639         result->state = COMPOSITE_STATE_IN_PROGRESS;
640         result->async.fn = NULL;
641         result->event_ctx = samr_pipe->conn->event_ctx;
642
643         state = talloc(result, struct samr_getuserdomgroups_state);
644         if (state == NULL) goto failed;
645         result->private_data = state;
646         state->ctx = result;
647
648         state->samr_pipe = samr_pipe;
649
650         state->user_handle = talloc(state, struct policy_handle);
651         if (state->user_handle == NULL) goto failed;
652
653         state->o.in.domain_handle = domain_handle;
654         state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
655         state->o.in.rid = rid;
656         state->o.out.user_handle = state->user_handle;
657
658         req = dcerpc_samr_OpenUser_send(state->samr_pipe, state, &state->o);
659         if (req == NULL) goto failed;
660
661         req->async.callback = samr_usergroups_recv_open;
662         req->async.private = state;
663         return result;
664
665  failed:
666         talloc_free(result);
667         return NULL;
668 }
669                                               
670 static void samr_usergroups_recv_open(struct rpc_request *req)
671 {
672         struct samr_getuserdomgroups_state *state =
673                 talloc_get_type(req->async.private,
674                                 struct samr_getuserdomgroups_state);
675
676         state->ctx->status = dcerpc_ndr_request_recv(req);
677         if (!composite_is_ok(state->ctx)) return;
678         state->ctx->status = state->o.out.result;
679         if (!composite_is_ok(state->ctx)) return;
680
681         state->g.in.user_handle = state->user_handle;
682
683         req = dcerpc_samr_GetGroupsForUser_send(state->samr_pipe, state,
684                                                 &state->g);
685         composite_continue_rpc(state->ctx, req, samr_usergroups_recv_groups,
686                                state);
687 }
688
689 static void samr_usergroups_recv_groups(struct rpc_request *req)
690 {
691         struct samr_getuserdomgroups_state *state =
692                 talloc_get_type(req->async.private,
693                                 struct samr_getuserdomgroups_state);
694
695         state->ctx->status = dcerpc_ndr_request_recv(req);
696         if (!composite_is_ok(state->ctx)) return;
697         state->ctx->status = state->g.out.result;
698         if (!composite_is_ok(state->ctx)) return;
699
700         state->c.in.handle = state->user_handle;
701         state->c.out.handle = state->user_handle;
702
703         req = dcerpc_samr_Close_send(state->samr_pipe, state, &state->c);
704         composite_continue_rpc(state->ctx, req, samr_usergroups_recv_close,
705                                state);
706 }
707
708 static void samr_usergroups_recv_close(struct rpc_request *req)
709 {
710         struct samr_getuserdomgroups_state *state =
711                 talloc_get_type(req->async.private,
712                                 struct samr_getuserdomgroups_state);
713
714         state->ctx->status = dcerpc_ndr_request_recv(req);
715         if (!composite_is_ok(state->ctx)) return;
716         state->ctx->status = state->c.out.result;
717         if (!composite_is_ok(state->ctx)) return;
718
719         composite_done(state->ctx);
720 }
721
722 NTSTATUS wb_samr_userdomgroups_recv(struct composite_context *ctx,
723                                     TALLOC_CTX *mem_ctx,
724                                     int *num_rids, uint32_t **rids)
725 {
726         struct samr_getuserdomgroups_state *state =
727                 talloc_get_type(ctx->private_data,
728                                 struct samr_getuserdomgroups_state);
729
730         int i;
731         NTSTATUS status = composite_wait(ctx);
732         if (!NT_STATUS_IS_OK(status)) goto done;
733
734         *num_rids = state->g.out.rids->count;
735         *rids = talloc_array(mem_ctx, uint32_t, *num_rids);
736         if (*rids == NULL) {
737                 status = NT_STATUS_NO_MEMORY;
738                 goto done;
739         }
740
741         for (i=0; i<*num_rids; i++) {
742                 (*rids)[i] = state->g.out.rids->rids[i].rid;
743         }
744
745  done:
746         talloc_free(ctx);
747         return status;
748 }