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