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