r23792: convert Samba4 to GPLv3
[mdw/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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19 /*
20   a composite API for finding a DC and its name
21 */
22
23 #include "includes.h"
24 #include "libcli/composite/composite.h"
25 #include "winbind/wb_async_helpers.h"
26
27 #include "lib/messaging/irpc.h"
28 #include "librpc/gen_ndr/irpc.h"
29 #include "auth/credentials/credentials.h"
30 #include "libcli/security/security.h"
31 #include "libcli/auth/libcli_auth.h"
32 #include "librpc/gen_ndr/ndr_netlogon_c.h"
33 #include "librpc/gen_ndr/ndr_lsa_c.h"
34 #include "librpc/gen_ndr/ndr_samr_c.h"
35
36 #include "winbind/wb_helper.h"
37
38 struct get_schannel_creds_state {
39         struct cli_credentials *wks_creds;
40         struct dcerpc_pipe *p;
41         struct netr_ServerReqChallenge r;
42
43         struct creds_CredentialState *creds_state;
44         struct netr_Credential netr_cred;
45         uint32_t negotiate_flags;
46         struct netr_ServerAuthenticate2 a;
47 };
48
49 static void get_schannel_creds_recv_anonbind(struct composite_context *creq);
50 static void get_schannel_creds_recv_auth(struct rpc_request *req);
51 static void get_schannel_creds_recv_chal(struct rpc_request *req);
52 static void get_schannel_creds_recv_pipe(struct composite_context *ctx);
53
54 struct composite_context *wb_get_schannel_creds_send(TALLOC_CTX *mem_ctx,
55                                                      struct cli_credentials *wks_creds,
56                                                      struct smbcli_tree *tree,
57                                                      struct event_context *ev)
58 {
59         struct composite_context *c, *creq;
60         struct get_schannel_creds_state *state;
61
62         c = composite_create(mem_ctx, ev);
63         if (c == NULL) goto failed;
64
65         state = talloc(c, struct get_schannel_creds_state);
66         if (state == NULL) {
67                 c->status = NT_STATUS_NO_MEMORY;
68                 goto failed;
69         }
70
71         c->private_data = state;
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, 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_data,
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_data,
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 = composite_create(mem_ctx, lsa_pipe->conn->event_ctx);
269         if (result == NULL) goto failed;
270
271         state = talloc(result, struct lsa_lookupsids_state);
272         if (state == NULL) goto failed;
273         result->private_data = state;
274         state->ctx = result;
275
276         state->sids.num_sids = num_sids;
277         state->sids.sids = talloc_array(state, struct lsa_SidPtr, num_sids);
278         if (state->sids.sids == NULL) goto failed;
279
280         for (i=0; i<num_sids; i++) {
281                 state->sids.sids[i].sid = dom_sid_dup(state->sids.sids,
282                                                       sids[i]);
283                 if (state->sids.sids[i].sid == NULL) goto failed;
284         }
285
286         state->count = 0;
287         state->num_sids = num_sids;
288         state->names.count = 0;
289         state->names.names = NULL;
290
291         state->r.in.handle = handle;
292         state->r.in.sids = &state->sids;
293         state->r.in.names = &state->names;
294         state->r.in.level = 1;
295         state->r.in.count = &state->count;
296         state->r.out.names = &state->names;
297         state->r.out.count = &state->count;
298
299         req = dcerpc_lsa_LookupSids_send(lsa_pipe, state, &state->r);
300         if (req == NULL) goto failed;
301
302         req->async.callback = lsa_lookupsids_recv_names;
303         req->async.private_data = state;
304         return result;
305
306  failed:
307         talloc_free(result);
308         return NULL;
309 }
310
311 static void lsa_lookupsids_recv_names(struct rpc_request *req)
312 {
313         struct lsa_lookupsids_state *state =
314                 talloc_get_type(req->async.private_data,
315                                 struct lsa_lookupsids_state);
316         int i;
317
318         state->ctx->status = dcerpc_ndr_request_recv(req);
319         if (!composite_is_ok(state->ctx)) return;
320         state->ctx->status = state->r.out.result;
321         if (!NT_STATUS_IS_OK(state->ctx->status) &&
322             !NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
323                 composite_error(state->ctx, state->ctx->status);
324                 return;
325         }
326
327         state->result = talloc_array(state, struct wb_sid_object *,
328                                      state->num_sids);
329         if (composite_nomem(state->result, state->ctx)) return;
330
331         for (i=0; i<state->num_sids; i++) {
332                 struct lsa_TranslatedName *name =
333                         &state->r.out.names->names[i];
334                 struct lsa_DomainInfo *dom;
335
336                 state->result[i] = talloc_zero(state->result,
337                                                struct wb_sid_object);
338                 if (composite_nomem(state->result[i], state->ctx)) return;
339
340                 state->result[i]->type = name->sid_type;
341                 if (state->result[i]->type == SID_NAME_UNKNOWN) {
342                         continue;
343                 }
344
345                 if (name->sid_index >= state->r.out.domains->count) {
346                         composite_error(state->ctx,
347                                         NT_STATUS_INVALID_PARAMETER);
348                         return;
349                 }
350
351                 dom = &state->r.out.domains->domains[name->sid_index];
352                 state->result[i]->domain = talloc_reference(state->result[i],
353                                                             dom->name.string);
354                 if ((name->sid_type == SID_NAME_DOMAIN) ||
355                     (name->name.string == NULL)) {
356                         state->result[i]->name =
357                                 talloc_strdup(state->result[i], "");
358                 } else {
359                         state->result[i]->name =
360                                 talloc_steal(state->result[i],
361                                              name->name.string);
362                 }
363
364                 if (composite_nomem(state->result[i]->name, state->ctx)) {
365                         return;
366                 }
367         }
368
369         composite_done(state->ctx);
370 }
371
372 NTSTATUS wb_lsa_lookupsids_recv(struct composite_context *c,
373                                 TALLOC_CTX *mem_ctx,
374                                 struct wb_sid_object ***names)
375 {
376         NTSTATUS status = composite_wait(c);
377         if (NT_STATUS_IS_OK(status)) {
378                 struct lsa_lookupsids_state *state =
379                         talloc_get_type(c->private_data,
380                                         struct lsa_lookupsids_state);
381                 *names = talloc_steal(mem_ctx, state->result);
382         }
383         talloc_free(c);
384         return status;
385 }
386
387 NTSTATUS wb_lsa_lookupsids(TALLOC_CTX *mem_ctx,
388                            struct dcerpc_pipe *lsa_pipe,
389                            struct policy_handle *handle,
390                            int num_sids, const struct dom_sid **sids,
391                            struct wb_sid_object ***names)
392 {
393         struct composite_context *c =
394                 wb_lsa_lookupsids_send(mem_ctx, lsa_pipe, handle,
395                                        num_sids, sids);
396         return wb_lsa_lookupnames_recv(c, mem_ctx, names);
397 }
398
399                            
400
401 struct lsa_lookupnames_state {
402         struct composite_context *ctx;
403         uint32_t num_names;
404         struct lsa_LookupNames r;
405         struct lsa_TransSidArray sids;
406         uint32_t count;
407         struct wb_sid_object **result;
408 };
409
410 static void lsa_lookupnames_recv_sids(struct rpc_request *req);
411
412 struct composite_context *wb_lsa_lookupnames_send(TALLOC_CTX *mem_ctx,
413                                                   struct dcerpc_pipe *lsa_pipe,
414                                                   struct policy_handle *handle,
415                                                   int num_names,
416                                                   const char **names)
417 {
418         struct composite_context *result;
419         struct rpc_request *req;
420         struct lsa_lookupnames_state *state;
421
422         struct lsa_String *lsa_names;
423         int i;
424
425         result = composite_create(mem_ctx, lsa_pipe->conn->event_ctx);
426         if (result == NULL) goto failed;
427
428         state = talloc(result, struct lsa_lookupnames_state);
429         if (state == NULL) goto failed;
430         result->private_data = state;
431         state->ctx = result;
432
433         state->sids.count = 0;
434         state->sids.sids = NULL;
435         state->num_names = num_names;
436         state->count = 0;
437
438         lsa_names = talloc_array(state, struct lsa_String, num_names);
439         if (lsa_names == NULL) goto failed;
440
441         for (i=0; i<num_names; i++) {
442                 lsa_names[i].string = names[i];
443         }
444
445         state->r.in.handle = handle;
446         state->r.in.num_names = num_names;
447         state->r.in.names = lsa_names;
448         state->r.in.sids = &state->sids;
449         state->r.in.level = 1;
450         state->r.in.count = &state->count;
451         state->r.out.count = &state->count;
452         state->r.out.sids = &state->sids;
453
454         req = dcerpc_lsa_LookupNames_send(lsa_pipe, state, &state->r);
455         if (req == NULL) goto failed;
456
457         req->async.callback = lsa_lookupnames_recv_sids;
458         req->async.private_data = state;
459         return result;
460
461  failed:
462         talloc_free(result);
463         return NULL;
464 }
465
466 static void lsa_lookupnames_recv_sids(struct rpc_request *req)
467 {
468         struct lsa_lookupnames_state *state =
469                 talloc_get_type(req->async.private_data,
470                                 struct lsa_lookupnames_state);
471         int i;
472
473         state->ctx->status = dcerpc_ndr_request_recv(req);
474         if (!composite_is_ok(state->ctx)) return;
475         state->ctx->status = state->r.out.result;
476         if (!NT_STATUS_IS_OK(state->ctx->status) &&
477             !NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
478                 composite_error(state->ctx, state->ctx->status);
479                 return;
480         }
481
482         state->result = talloc_array(state, struct wb_sid_object *,
483                                      state->num_names);
484         if (composite_nomem(state->result, state->ctx)) return;
485
486         for (i=0; i<state->num_names; i++) {
487                 struct lsa_TranslatedSid *sid = &state->r.out.sids->sids[i];
488                 struct lsa_DomainInfo *dom;
489
490                 state->result[i] = talloc_zero(state->result,
491                                                struct wb_sid_object);
492                 if (composite_nomem(state->result[i], state->ctx)) return;
493
494                 state->result[i]->type = sid->sid_type;
495                 if (state->result[i]->type == SID_NAME_UNKNOWN) {
496                         continue;
497                 }
498
499                 if (sid->sid_index >= state->r.out.domains->count) {
500                         composite_error(state->ctx,
501                                         NT_STATUS_INVALID_PARAMETER);
502                         return;
503                 }
504
505                 dom = &state->r.out.domains->domains[sid->sid_index];
506
507                 state->result[i]->sid = dom_sid_add_rid(state->result[i],
508                                                         dom->sid, sid->rid);
509         }
510
511         composite_done(state->ctx);
512 }
513
514 NTSTATUS wb_lsa_lookupnames_recv(struct composite_context *c,
515                                  TALLOC_CTX *mem_ctx,
516                                  struct wb_sid_object ***sids)
517 {
518         NTSTATUS status = composite_wait(c);
519         if (NT_STATUS_IS_OK(status)) {
520                 struct lsa_lookupnames_state *state =
521                         talloc_get_type(c->private_data,
522                                         struct lsa_lookupnames_state);
523                 *sids = talloc_steal(mem_ctx, state->result);
524         }
525         talloc_free(c);
526         return status;
527 }
528
529 NTSTATUS wb_lsa_lookupnames(TALLOC_CTX *mem_ctx,
530                             struct dcerpc_pipe *lsa_pipe, 
531                             struct policy_handle *handle,
532                             int num_names, const char **names,
533                             struct wb_sid_object ***sids)
534 {
535         struct composite_context *c =
536                 wb_lsa_lookupnames_send(mem_ctx, lsa_pipe, handle,
537                                         num_names, names);
538         return wb_lsa_lookupnames_recv(c, mem_ctx, sids);
539 }
540
541 #if 0
542
543 struct cmd_checkmachacc_state {
544         struct composite_context *ctx;
545         struct wbsrv_call *call;
546         struct wbsrv_domain *domain;
547 };
548
549 static void cmd_checkmachacc_recv_init(struct composite_context *ctx);
550
551  struct composite_context *wb_cmd_checkmachacc_send(struct wbsrv_call *call)
552 {
553         struct composite_context *result, *ctx;
554         struct cmd_checkmachacc_state *state;
555         struct wbsrv_service *service = call->wbconn->listen_socket->service;
556
557         result = composite_create(mem_ctx, call->event_ctx;
558         if (result == NULL) goto failed;
559
560         state = talloc(result, struct cmd_checkmachacc_state);
561         if (state == NULL) goto failed;
562         state->ctx = result;
563         result->private_data = state;
564         state->call = call;
565
566         state->domain = service->domains;
567
568         ctx = wb_init_domain_send(service, state->domain);
569         if (ctx == NULL) goto failed;
570         ctx->async.fn = cmd_checkmachacc_recv_init;
571         ctx->async.private_data = state;
572
573         return result;
574
575  failed:
576         talloc_free(result);
577         return NULL;
578 }
579
580 static void cmd_checkmachacc_recv_init(struct composite_context *ctx)
581 {
582         struct cmd_checkmachacc_state *state =
583                 talloc_get_type(ctx->async.private_data,
584                                 struct cmd_checkmachacc_state);
585
586         state->ctx->status = wb_init_domain_recv(ctx);
587         if (!composite_is_ok(state->ctx)) return;
588
589         composite_done(state->ctx);
590 }
591
592  NTSTATUS wb_cmd_checkmachacc_recv(struct composite_context *c)
593 {
594         NTSTATUS status = composite_wait(c);
595         talloc_free(c);
596         return status;
597 }
598
599  NTSTATUS wb_cmd_checkmachacc(struct wbsrv_call *call)
600 {
601         struct composite_context *c = wb_cmd_checkmachacc_send(call);
602         return wb_cmd_checkmachacc_recv(c);
603 }
604 #endif
605
606 struct samr_getuserdomgroups_state {
607         struct composite_context *ctx;
608         struct dcerpc_pipe *samr_pipe;
609
610         int num_rids;
611         uint32_t *rids;
612
613         struct policy_handle *user_handle;
614         struct samr_OpenUser o;
615         struct samr_GetGroupsForUser g;
616         struct samr_Close c;
617 };
618
619 static void samr_usergroups_recv_open(struct rpc_request *req);
620 static void samr_usergroups_recv_groups(struct rpc_request *req);
621 static void samr_usergroups_recv_close(struct rpc_request *req);
622
623 struct composite_context *wb_samr_userdomgroups_send(TALLOC_CTX *mem_ctx,
624                                                      struct dcerpc_pipe *samr_pipe,
625                                                      struct policy_handle *domain_handle,
626                                                      uint32_t rid)
627 {
628         struct composite_context *result;
629         struct rpc_request *req;
630         struct samr_getuserdomgroups_state *state;
631
632         result = composite_create(mem_ctx, samr_pipe->conn->event_ctx);
633         if (result == NULL) goto failed;
634
635         state = talloc(result, struct samr_getuserdomgroups_state);
636         if (state == NULL) goto failed;
637         result->private_data = state;
638         state->ctx = result;
639
640         state->samr_pipe = samr_pipe;
641
642         state->user_handle = talloc(state, struct policy_handle);
643         if (state->user_handle == NULL) goto failed;
644
645         state->o.in.domain_handle = domain_handle;
646         state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
647         state->o.in.rid = rid;
648         state->o.out.user_handle = state->user_handle;
649
650         req = dcerpc_samr_OpenUser_send(state->samr_pipe, state, &state->o);
651         if (req == NULL) goto failed;
652
653         req->async.callback = samr_usergroups_recv_open;
654         req->async.private_data = state;
655         return result;
656
657  failed:
658         talloc_free(result);
659         return NULL;
660 }
661                                               
662 static void samr_usergroups_recv_open(struct rpc_request *req)
663 {
664         struct samr_getuserdomgroups_state *state =
665                 talloc_get_type(req->async.private_data,
666                                 struct samr_getuserdomgroups_state);
667
668         state->ctx->status = dcerpc_ndr_request_recv(req);
669         if (!composite_is_ok(state->ctx)) return;
670         state->ctx->status = state->o.out.result;
671         if (!composite_is_ok(state->ctx)) return;
672
673         state->g.in.user_handle = state->user_handle;
674
675         req = dcerpc_samr_GetGroupsForUser_send(state->samr_pipe, state,
676                                                 &state->g);
677         composite_continue_rpc(state->ctx, req, samr_usergroups_recv_groups,
678                                state);
679 }
680
681 static void samr_usergroups_recv_groups(struct rpc_request *req)
682 {
683         struct samr_getuserdomgroups_state *state =
684                 talloc_get_type(req->async.private_data,
685                                 struct samr_getuserdomgroups_state);
686
687         state->ctx->status = dcerpc_ndr_request_recv(req);
688         if (!composite_is_ok(state->ctx)) return;
689         state->ctx->status = state->g.out.result;
690         if (!composite_is_ok(state->ctx)) return;
691
692         state->c.in.handle = state->user_handle;
693         state->c.out.handle = state->user_handle;
694
695         req = dcerpc_samr_Close_send(state->samr_pipe, state, &state->c);
696         composite_continue_rpc(state->ctx, req, samr_usergroups_recv_close,
697                                state);
698 }
699
700 static void samr_usergroups_recv_close(struct rpc_request *req)
701 {
702         struct samr_getuserdomgroups_state *state =
703                 talloc_get_type(req->async.private_data,
704                                 struct samr_getuserdomgroups_state);
705
706         state->ctx->status = dcerpc_ndr_request_recv(req);
707         if (!composite_is_ok(state->ctx)) return;
708         state->ctx->status = state->c.out.result;
709         if (!composite_is_ok(state->ctx)) return;
710
711         composite_done(state->ctx);
712 }
713
714 NTSTATUS wb_samr_userdomgroups_recv(struct composite_context *ctx,
715                                     TALLOC_CTX *mem_ctx,
716                                     int *num_rids, uint32_t **rids)
717 {
718         struct samr_getuserdomgroups_state *state =
719                 talloc_get_type(ctx->private_data,
720                                 struct samr_getuserdomgroups_state);
721
722         int i;
723         NTSTATUS status = composite_wait(ctx);
724         if (!NT_STATUS_IS_OK(status)) goto done;
725
726         *num_rids = state->g.out.rids->count;
727         *rids = talloc_array(mem_ctx, uint32_t, *num_rids);
728         if (*rids == NULL) {
729                 status = NT_STATUS_NO_MEMORY;
730                 goto done;
731         }
732
733         for (i=0; i<*num_rids; i++) {
734                 (*rids)[i] = state->g.out.rids->rids[i].rid;
735         }
736
737  done:
738         talloc_free(ctx);
739         return status;
740 }