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