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