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