779180174f205977edad4156f30cc175892ee02e
[metze/samba/wip.git] / librpc / rpc / binding_handle.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    dcerpc binding handle functions
5
6    Copyright (C) Stefan Metzmacher 2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include <tevent.h>
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "librpc/rpc/dcerpc.h"
26 #include "rpc_common.h"
27
28 struct dcerpc_binding_handle {
29         void *private_data;
30         const struct dcerpc_binding_handle_ops *ops;
31         const char *location;
32         const struct GUID *object;
33         const struct ndr_interface_table *table;
34         struct tevent_context *sync_ev;
35 };
36
37 static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
38 {
39         return 0;
40 }
41
42 struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
43                                         const struct dcerpc_binding_handle_ops *ops,
44                                         const struct GUID *object,
45                                         const struct ndr_interface_table *table,
46                                         void *pstate,
47                                         size_t psize,
48                                         const char *type,
49                                         const char *location)
50 {
51         struct dcerpc_binding_handle *h;
52         void **ppstate = (void **)pstate;
53         void *state;
54
55         h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
56         if (h == NULL) {
57                 return NULL;
58         }
59         h->ops          = ops;
60         h->location     = location;
61         h->object       = object;
62         h->table        = table;
63
64         state = talloc_zero_size(h, psize);
65         if (state == NULL) {
66                 talloc_free(h);
67                 return NULL;
68         }
69         talloc_set_name_const(state, type);
70
71         h->private_data = state;
72
73         talloc_set_destructor(h, dcerpc_binding_handle_destructor);
74
75         *ppstate = state;
76         return h;
77 }
78
79 void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
80 {
81         return h->private_data;
82 }
83
84 void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
85                                        struct tevent_context *ev)
86 {
87         h->sync_ev = ev;
88 }
89
90 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
91 {
92         return h->ops->is_connected(h);
93 }
94
95 uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
96                                            uint32_t timeout)
97 {
98         return h->ops->set_timeout(h, timeout);
99 }
100
101 void dcerpc_binding_handle_auth_info(struct dcerpc_binding_handle *h,
102                                      enum dcerpc_AuthType *auth_type,
103                                      enum dcerpc_AuthLevel *auth_level)
104 {
105         enum dcerpc_AuthType _auth_type;
106         enum dcerpc_AuthLevel _auth_level;
107
108         if (auth_type == NULL) {
109                 auth_type = &_auth_type;
110         }
111
112         if (auth_level == NULL) {
113                 auth_level = &_auth_level;
114         }
115
116         *auth_type = DCERPC_AUTH_TYPE_NONE;
117         *auth_level = DCERPC_AUTH_LEVEL_NONE;
118
119         if (h->ops->auth_info == NULL) {
120                 return;
121         }
122
123         h->ops->auth_info(h, auth_type, auth_level);
124 }
125
126 struct dcerpc_binding_handle_raw_call_state {
127         const struct dcerpc_binding_handle_ops *ops;
128         struct tevent_context *ev;
129         struct tevent_req *subreq;
130 };
131
132 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
133
134 struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
135                                                 struct tevent_context *ev,
136                                                 struct dcerpc_binding_handle *h,
137                                                 const struct GUID *object,
138                                                 uint32_t opnum,
139                                                 uint32_t in_flags,
140                                                 const uint8_t *in_data,
141                                                 size_t in_length)
142 {
143         struct tevent_req *req;
144         struct dcerpc_binding_handle_raw_call_state *state;
145
146         req = tevent_req_create(mem_ctx, &state,
147                                 struct dcerpc_binding_handle_raw_call_state);
148         if (req == NULL) {
149                 return NULL;
150         }
151         state->ops = h->ops;
152         state->ev = ev;
153
154         if (h->object != NULL) {
155                 /*
156                  * If an object is set on the binding handle,
157                  * per request object passing is not allowed.
158                  */
159                 if (object != NULL) {
160                         tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
161                         return tevent_req_post(req, ev);
162                 }
163
164                 /*
165                  * We use the object from the binding handle
166                  */
167                 object = h->object;
168         }
169
170         if (state->ops->raw_call_in_send == NULL) {
171                 if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
172                         tevent_req_nterror(req, NT_STATUS_RPC_CANNOT_SUPPORT);
173                         return tevent_req_post(req, ev);
174                 }
175         }
176
177         state->subreq = state->ops->raw_call_send(state, ev, h,
178                                                   object, opnum,
179                                                   in_flags, in_data, in_length);
180         if (tevent_req_nomem(state->subreq, req)) {
181                 return tevent_req_post(req, ev);
182         }
183         tevent_req_set_callback(state->subreq,
184                                 dcerpc_binding_handle_raw_call_done,
185                                 req);
186
187         return req;
188 }
189
190 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
191 {
192         struct tevent_req *req =
193                 tevent_req_callback_data(subreq,
194                 struct tevent_req);
195
196         if (tevent_req_is_in_progress(subreq)) {
197                 tevent_req_notify_callback(req);
198                 return;
199         }
200
201         tevent_req_done(req);
202 }
203
204 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
205                                              TALLOC_CTX *mem_ctx,
206                                              uint8_t **out_data,
207                                              size_t *out_length,
208                                              uint32_t *out_flags)
209 {
210         struct dcerpc_binding_handle_raw_call_state *state =
211                 tevent_req_data(req,
212                 struct dcerpc_binding_handle_raw_call_state);
213         NTSTATUS error;
214
215         if (!tevent_req_is_in_progress(req)) {
216                 if (tevent_req_is_nterror(req, &error)) {
217                         tevent_req_received(req);
218                         return error;
219                 }
220         }
221
222         error = state->ops->raw_call_recv(state->subreq,
223                                           mem_ctx,
224                                           out_data,
225                                           out_length,
226                                           out_flags);
227         if (!NT_STATUS_IS_OK(error)) {
228                 tevent_req_received(req);
229                 return error;
230         }
231
232         if (tevent_req_is_in_progress(state->subreq)) {
233                 return NT_STATUS_OK;
234         }
235
236         tevent_req_received(req);
237         return NT_STATUS_OK;
238 }
239
240 NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
241                                         const struct GUID *object,
242                                         uint32_t opnum,
243                                         uint32_t in_flags,
244                                         const uint8_t *in_data,
245                                         size_t in_length,
246                                         TALLOC_CTX *mem_ctx,
247                                         uint8_t **out_data,
248                                         size_t *out_length,
249                                         uint32_t *out_flags)
250 {
251         TALLOC_CTX *frame = talloc_stackframe();
252         struct tevent_context *ev;
253         struct tevent_req *subreq;
254         NTSTATUS status = NT_STATUS_NO_MEMORY;
255
256         /*
257          * TODO: allow only one sync call
258          */
259
260         if (h->sync_ev) {
261                 ev = h->sync_ev;
262         } else {
263                 ev = samba_tevent_context_init(frame);
264         }
265         if (ev == NULL) {
266                 goto fail;
267         }
268
269         if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
270                 talloc_free(frame);
271                 return NT_STATUS_INVALID_PARAMETER_MIX;
272         }
273
274         subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
275                                                      h, object, opnum,
276                                                      in_flags,
277                                                      in_data,
278                                                      in_length);
279         if (subreq == NULL) {
280                 goto fail;
281         }
282
283         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
284                 goto fail;
285         }
286
287         status = dcerpc_binding_handle_raw_call_recv(subreq,
288                                                      mem_ctx,
289                                                      out_data,
290                                                      out_length,
291                                                      out_flags);
292 fail:
293         TALLOC_FREE(frame);
294         return status;
295 }
296
297 struct dcerpc_binding_handle_raw_call_in_state {
298         const struct dcerpc_binding_handle_ops *ops;
299         struct tevent_context *ev;
300         struct tevent_req *subreq;
301 };
302
303 static void dcerpc_binding_handle_raw_call_in_done(struct tevent_req *subreq);
304
305 struct tevent_req *dcerpc_binding_handle_raw_call_in_send(TALLOC_CTX *mem_ctx,
306                                                 struct tevent_context *ev,
307                                                 struct tevent_req *raw_call_req,
308                                                 uint32_t in_flags,
309                                                 const uint8_t *in_data,
310                                                 size_t in_length)
311 {
312         struct dcerpc_binding_handle_raw_call_state *raw_call_state =
313                 tevent_req_data(raw_call_req,
314                 struct dcerpc_binding_handle_raw_call_state);
315         struct tevent_req *req;
316         struct dcerpc_binding_handle_raw_call_in_state *state;
317
318         req = tevent_req_create(mem_ctx, &state,
319                                 struct dcerpc_binding_handle_raw_call_in_state);
320         if (req == NULL) {
321                 return NULL;
322         }
323         state->ops = raw_call_state->ops;
324         state->ev = ev;
325
326         if (state->ev != raw_call_state->ev) {
327                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
328                 return tevent_req_post(req, ev);
329         }
330
331         if (state->ops->raw_call_in_send == NULL) {
332                 tevent_req_nterror(req, NT_STATUS_RPC_CANNOT_SUPPORT);
333                 return tevent_req_post(req, ev);
334         }
335
336         state->subreq = state->ops->raw_call_in_send(state, ev,
337                                                      raw_call_state->subreq,
338                                                      in_flags,
339                                                      in_data,
340                                                      in_length);
341         if (tevent_req_nomem(state->subreq, req)) {
342                 return tevent_req_post(req, ev);
343         }
344
345         tevent_req_set_callback(state->subreq,
346                                 dcerpc_binding_handle_raw_call_in_done,
347                                 req);
348         return req;
349 }
350
351 static void dcerpc_binding_handle_raw_call_in_done(struct tevent_req *subreq)
352 {
353         struct tevent_req *req =
354                 tevent_req_callback_data(subreq,
355                 struct tevent_req);
356
357         if (tevent_req_is_in_progress(subreq)) {
358                 tevent_req_notify_callback(req);
359                 return;
360         }
361
362         tevent_req_done(req);
363 }
364
365 NTSTATUS dcerpc_binding_handle_raw_call_in_recv(struct tevent_req *req)
366 {
367         struct dcerpc_binding_handle_raw_call_in_state *state =
368                 tevent_req_data(req,
369                 struct dcerpc_binding_handle_raw_call_in_state);
370         NTSTATUS error;
371
372         if (!tevent_req_is_in_progress(req)) {
373                 if (tevent_req_is_nterror(req, &error)) {
374                         tevent_req_received(req);
375                         return error;
376                 }
377         }
378
379         error = state->ops->raw_call_in_recv(state->subreq);
380         if (!NT_STATUS_IS_OK(error)) {
381                 tevent_req_received(req);
382                 return error;
383         }
384
385         if (tevent_req_is_in_progress(state->subreq)) {
386                 return NT_STATUS_OK;
387         }
388
389         tevent_req_received(req);
390         return error;
391 }
392
393 struct dcerpc_binding_handle_disconnect_state {
394         const struct dcerpc_binding_handle_ops *ops;
395 };
396
397 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
398
399 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
400                                                 struct tevent_context *ev,
401                                                 struct dcerpc_binding_handle *h)
402 {
403         struct tevent_req *req;
404         struct dcerpc_binding_handle_disconnect_state *state;
405         struct tevent_req *subreq;
406
407         req = tevent_req_create(mem_ctx, &state,
408                                 struct dcerpc_binding_handle_disconnect_state);
409         if (req == NULL) {
410                 return NULL;
411         }
412
413         state->ops = h->ops;
414
415         subreq = state->ops->disconnect_send(state, ev, h);
416         if (tevent_req_nomem(subreq, req)) {
417                 return tevent_req_post(req, ev);
418         }
419         tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
420
421         return req;
422 }
423
424 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
425 {
426         struct tevent_req *req = tevent_req_callback_data(subreq,
427                                  struct tevent_req);
428         struct dcerpc_binding_handle_disconnect_state *state =
429                 tevent_req_data(req,
430                 struct dcerpc_binding_handle_disconnect_state);
431         NTSTATUS error;
432
433         error = state->ops->disconnect_recv(subreq);
434         TALLOC_FREE(subreq);
435         if (tevent_req_nterror(req, error)) {
436                 return;
437         }
438
439         tevent_req_done(req);
440 }
441
442 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
443 {
444         NTSTATUS error;
445
446         if (tevent_req_is_nterror(req, &error)) {
447                 tevent_req_received(req);
448                 return error;
449         }
450
451         tevent_req_received(req);
452         return NT_STATUS_OK;
453 }
454
455 struct dcerpc_binding_handle_call_params_state {
456         struct dcerpc_binding_handle *h;
457         const struct ndr_interface_call *call;
458         struct dcerpc_binding_handle_call_params *params;
459         uint32_t in_flags;
460         struct ndr_push *push;
461         DATA_BLOB request;
462         struct tevent_req *subreq;
463         DATA_BLOB response;
464         struct ndr_pull *pull;
465
466         struct dcerpc_pipe_handle *ph;
467         struct dcerpc_pipe_handle_connection *pc;
468         const struct ndr_interface_call_pipe *call_pipe;
469         uint32_t in_pipe_idx;
470         uint32_t out_pipe_idx;
471 };
472
473 static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq);
474 static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req);
475 static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq);
476 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req);
477 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p);
478
479 struct tevent_req *dcerpc_binding_handle_call_params_send(TALLOC_CTX *mem_ctx,
480                                 struct tevent_context *ev,
481                                 struct dcerpc_binding_handle *h,
482                                 const struct GUID *object,
483                                 const struct ndr_interface_table *table,
484                                 uint32_t opnum,
485                                 struct dcerpc_binding_handle_call_params *params)
486 {
487         struct tevent_req *req;
488         struct dcerpc_binding_handle_call_params_state *state;
489         enum ndr_err_code ndr_err;
490
491         req = tevent_req_create(mem_ctx, &state,
492                                 struct dcerpc_binding_handle_call_params_state);
493         if (req == NULL) {
494                 return NULL;
495         }
496
497         if (table != h->table) {
498                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
499                 return tevent_req_post(req, ev);
500         }
501
502         if (opnum >= table->num_calls) {
503                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
504                 return tevent_req_post(req, ev);
505         }
506
507         state->h = h;
508         state->call = &table->calls[opnum];
509         state->params = params;
510
511         if (params->in.num_pipes != state->call->in_pipes.num_pipes) {
512                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
513                 return tevent_req_post(req, ev);
514         }
515
516         if (params->out.num_pipes != state->call->out_pipes.num_pipes) {
517                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
518                 return tevent_req_post(req, ev);
519         }
520
521         /* setup for a ndr_push_* call */
522         state->push = ndr_push_init_ctx(state);
523         if (tevent_req_nomem(state->push, req)) {
524                 return tevent_req_post(req, ev);
525         }
526
527         if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
528                 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
529         }
530
531         if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
532                 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
533                 state->in_flags |= LIBNDR_FLAG_BIGENDIAN;
534         }
535
536         if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
537                 state->push->flags |= LIBNDR_FLAG_NDR64;
538         }
539
540         if (h->ops->do_ndr_print) {
541                 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
542                                      state->params->r_ptr, state->call);
543         }
544
545         /* push the structure into a blob */
546         ndr_err = state->call->ndr_push(state->push, NDR_IN, state->params->r_ptr);
547         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
548                 NTSTATUS error;
549                 error = ndr_map_error2ntstatus(ndr_err);
550                 if (h->ops->ndr_push_failed) {
551                         h->ops->ndr_push_failed(h, error,
552                                                 state->params->r_ptr,
553                                                 state->call);
554                 }
555                 tevent_req_nterror(req, error);
556                 return tevent_req_post(req, ev);
557         }
558
559         /* retrieve the blob */
560         state->request = ndr_push_blob(state->push);
561
562         if (h->ops->ndr_validate_in) {
563                 NTSTATUS error;
564                 error = h->ops->ndr_validate_in(h, state,
565                                                 &state->request,
566                                                 state->call);
567                 if (!NT_STATUS_IS_OK(error)) {
568                         tevent_req_nterror(req, error);
569                         return tevent_req_post(req, ev);
570                 }
571         }
572
573         if (params->in.num_pipes != 0) {
574                 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
575
576                 /*
577                  * push alignment for the next pipe chunk
578                  */
579                 ndr_err = ndr_push_align(state->push, 5);
580                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
581                         NTSTATUS error;
582                         error = ndr_map_error2ntstatus(ndr_err);
583                         tevent_req_nterror(req, error);
584                         return tevent_req_post(req, ev);
585                 }
586         }
587
588         if (params->out.num_pipes != 0) {
589                 /*
590                  * even if we only have output pipes we need to indicate that
591                  * we want to get incomplete results
592                  */
593                 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
594         }
595
596         if (state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
597                 dcerpc_binding_handle_call_params_pipe_setup(req);
598                 if (!tevent_req_is_in_progress(req)) {
599                         return tevent_req_post(req, ev);
600                 }
601         }
602
603         /* retrieve the blob - including possible pipe chunk alignment */
604         state->request = ndr_push_blob(state->push);
605
606         state->subreq = dcerpc_binding_handle_raw_call_send(state, ev,
607                                                 h, object, opnum,
608                                                 state->in_flags,
609                                                 state->request.data,
610                                                 state->request.length);
611         if (tevent_req_nomem(state->subreq, req)) {
612                 return tevent_req_post(req, ev);
613         }
614         tevent_req_set_callback(state->subreq,
615                                 dcerpc_binding_handle_call_params_done,
616                                 req);
617
618         if (!(state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
619                 /*
620                  * we didn't ask for any pipes
621                  *
622                  * Indicate that all pipes are done.
623                  */
624                 state->in_pipe_idx = UINT32_MAX;
625                 state->out_pipe_idx = UINT32_MAX;
626                 return req;
627         }
628
629         /*
630          * If the subreq is already finished, the backend
631          * may not support LIBNDR_FLAG_INCOMPLETE_BUFFER
632          */
633         if (!tevent_req_is_in_progress(state->subreq)) {
634                 return req;
635         }
636
637         dcerpc_binding_handle_call_params_next_pipe(req);
638         if (!tevent_req_is_in_progress(req)) {
639                 return tevent_req_post(req, ev);
640         }
641
642         if (state->params->in.num_pipes == 0) {
643                 struct tevent_req *subreq;
644
645                 /*
646                  * We have only out pipes,
647                  * so indicate that we're done with sending in_data.
648                  */
649                 state->in_pipe_idx = UINT32_MAX;
650                 state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
651                 subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
652                                                                 state->subreq,
653                                                                 state->in_flags,
654                                                                 NULL, /* in_data */
655                                                                 0); /* in_length */
656                 if (tevent_req_nomem(subreq, req)) {
657                         return tevent_req_post(req, ev);
658                 }
659                 tevent_req_set_callback(subreq,
660                                         dcerpc_binding_handle_call_params_in_done,
661                                         req);
662                 return req;
663         }
664
665         return req;
666 }
667
668 static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq)
669 {
670         struct tevent_req *req = tevent_req_callback_data(subreq,
671                                  struct tevent_req);
672         NTSTATUS error;
673
674         error = dcerpc_binding_handle_raw_call_in_recv(subreq);
675         TALLOC_FREE(subreq);
676         if (tevent_req_nterror(req, error)) {
677                 return;
678         }
679
680         /*
681          * nothing to do here
682          */
683 }
684
685 static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req)
686 {
687         struct dcerpc_binding_handle_call_params_state *state =
688                 tevent_req_data(req,
689                 struct dcerpc_binding_handle_call_params_state);
690         struct dcerpc_binding_handle_call_params *params = state->params;
691         bool ok;
692
693         dcerpc_pipe_handle_connection_disconnect(state->pc);
694         state->pc = NULL;
695         state->call_pipe = NULL;
696
697         if (state->in_pipe_idx < params->in.num_pipes) {
698                 uint32_t idx = state->in_pipe_idx++;
699
700                 state->pc = params->in.pipes[idx];
701                 state->call_pipe = &state->call->in_pipes.pipes[idx];
702
703                 ok = dcerpc_pipe_handle_connection_push_connect(state->pc,
704                                         state->call_pipe->chunk_struct_name,
705                                         state->call_pipe->chunk_struct_size,
706                                         state->ph);
707                 if (!ok) {
708                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
709                         return;
710                 }
711
712                 return;
713         }
714         state->in_pipe_idx = UINT32_MAX;
715
716         if (state->out_pipe_idx < params->out.num_pipes) {
717                 uint32_t idx = state->out_pipe_idx++;
718
719                 state->pc = params->out.pipes[idx];
720                 state->call_pipe = &state->call->out_pipes.pipes[idx];
721
722                 ok = dcerpc_pipe_handle_connection_pull_connect(state->pc,
723                                         state->call_pipe->chunk_struct_name,
724                                         state->call_pipe->chunk_struct_size,
725                                         state->ph);
726                 if (!ok) {
727                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
728                         return;
729                 }
730
731                 return;
732         }
733         state->out_pipe_idx = UINT32_MAX;
734 }
735
736 static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq)
737 {
738         struct tevent_req *req = tevent_req_callback_data(subreq,
739                                  struct tevent_req);
740         struct dcerpc_binding_handle_call_params_state *state =
741                 tevent_req_data(req,
742                 struct dcerpc_binding_handle_call_params_state);
743         struct dcerpc_binding_handle *h = state->h;
744         NTSTATUS error;
745         uint32_t out_flags = 0;
746         enum ndr_err_code ndr_err;
747
748         error = dcerpc_binding_handle_raw_call_recv(subreq, state,
749                                                     &state->response.data,
750                                                     &state->response.length,
751                                                     &out_flags);
752         subreq = NULL;
753         if (!NT_STATUS_IS_OK(error)) {
754                 TALLOC_FREE(state->subreq);
755                 tevent_req_nterror(req, error);
756                 return;
757         }
758
759         if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
760                 TALLOC_FREE(state->subreq);
761         }
762
763         if (state->in_pipe_idx != UINT32_MAX) {
764                 /*
765                  * we haven't send all data yet,
766                  * this is a protocol error
767                  */
768                 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
769                 return;
770         }
771
772         if (state->pull == NULL) {
773                 state->pull = ndr_pull_init_blob(&state->response, state);
774                 if (tevent_req_nomem(state->pull, req)) {
775                         return;
776                 }
777                 state->pull->flags = state->push->flags;
778
779                 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
780                         state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
781                 } else {
782                         state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
783                 }
784
785                 if (out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
786                         state->pull->flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
787                 }
788         } else {
789                 if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
790                         state->pull->flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
791                 }
792
793                 ndr_err = ndr_pull_append(state->pull,
794                                           &state->response);
795                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
796                         error = ndr_map_error2ntstatus(ndr_err);
797                         if (h->ops->ndr_pull_failed) {
798                                 h->ops->ndr_pull_failed(h, error,
799                                                         &state->response,
800                                                         state->call);
801                         }
802                         tevent_req_nterror(req, error);
803                         return;
804                 }
805         }
806
807         if (state->out_pipe_idx != UINT32_MAX) {
808                 dcerpc_binding_handle_call_params_pipe_notify(state->ph);
809                 return;
810         }
811
812         state->pull->current_mem_ctx = state->params->r_mem;
813
814         /* pull the structure from the blob */
815         ndr_err = state->call->ndr_pull(state->pull, NDR_OUT,
816                                         state->params->r_ptr);
817         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
818                 error = ndr_map_error2ntstatus(ndr_err);
819                 if (h->ops->ndr_pull_failed) {
820                         h->ops->ndr_pull_failed(h, error,
821                                                 &state->response,
822                                                 state->call);
823                 }
824                 tevent_req_nterror(req, error);
825                 return;
826         }
827
828         if (h->ops->do_ndr_print) {
829                 h->ops->do_ndr_print(h, NDR_OUT,
830                                      state->params->r_ptr, state->call);
831         }
832
833         if (h->ops->ndr_validate_out) {
834                 error = h->ops->ndr_validate_out(h,
835                                                  state->pull,
836                                                  state->params->r_ptr,
837                                                  state->call);
838                 if (!NT_STATUS_IS_OK(error)) {
839                         tevent_req_nterror(req, error);
840                         return;
841                 }
842         }
843
844         tevent_req_done(req);
845 }
846
847 NTSTATUS dcerpc_binding_handle_call_params_recv(struct tevent_req *req)
848 {
849         return tevent_req_simple_recv_ntstatus(req);
850 }
851
852 struct dcerpc_binding_handle_call_params_pipe {
853         struct tevent_req *call_req;
854         struct tevent_req *pull_req;
855 };
856
857 struct dcerpc_binding_handle_call_params_push_state {
858         struct tevent_context *ev;
859         struct dcerpc_pipe_handle *p;
860         struct ndr_push *push;
861         DATA_BLOB chunk_blob;
862         bool is_last_chunk;
863 };
864
865 static int dcerpc_binding_handle_call_params_push_state_destructor(
866         struct dcerpc_binding_handle_call_params_push_state *state)
867 {
868         struct dcerpc_binding_handle_call_params_pipe *pp =
869                 dcerpc_pipe_handle_data(state->p,
870                 struct dcerpc_binding_handle_call_params_pipe);
871         struct dcerpc_binding_handle_call_params_state *call_state =
872                 tevent_req_data(pp->call_req,
873                 struct dcerpc_binding_handle_call_params_state);
874
875         dcerpc_pipe_handle_connection_disconnect(call_state->pc);
876         call_state->pc = NULL;
877         call_state->call_pipe = NULL;
878         return 0;
879 }
880
881 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq);
882
883 static struct tevent_req *dcerpc_binding_handle_call_params_push_send(TALLOC_CTX *mem_ctx,
884                                         struct tevent_context *ev,
885                                         struct dcerpc_pipe_handle *p,
886                                         const void *chunk_ptr)
887 {
888         struct dcerpc_binding_handle_call_params_pipe *pp =
889                 dcerpc_pipe_handle_data(p,
890                 struct dcerpc_binding_handle_call_params_pipe);
891         struct dcerpc_binding_handle_call_params_state *call_state =
892                 tevent_req_data(pp->call_req,
893                 struct dcerpc_binding_handle_call_params_state);
894         struct tevent_req *req;
895         struct dcerpc_binding_handle_call_params_push_state *state;
896         struct tevent_req *subreq;
897         enum ndr_err_code ndr_err;
898         const uint32_t *count = NULL;
899         bool is_last_pipe = false;
900
901         req = tevent_req_create(mem_ctx, &state,
902                                 struct dcerpc_binding_handle_call_params_push_state);
903         if (req == NULL) {
904                 return NULL;
905         }
906         state->ev = ev;
907         state->p = p;
908
909         talloc_set_destructor(state,
910                               dcerpc_binding_handle_call_params_push_state_destructor);
911
912         /* setup for a ndr_push_* call */
913         state->push = ndr_push_init_ctx(state);
914         if (tevent_req_nomem(state->push, req)) {
915                 return tevent_req_post(req, ev);
916         }
917
918         state->push->flags = call_state->push->flags;
919
920         //if (h->ops->do_ndr_print) {
921         //      h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
922         //                           state->params->r_ptr, state->call);
923         //}
924
925         /* push the structure into a blob */
926         ndr_err = call_state->call_pipe->ndr_push(state->push,
927                                                   NDR_SCALARS|NDR_BUFFERS,
928                                                   chunk_ptr);
929         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
930                 NTSTATUS error;
931                 error = ndr_map_error2ntstatus(ndr_err);
932                 //if (h->ops->ndr_push_failed) {
933                 //      h->ops->ndr_push_failed(h, error,
934                 //                              state->params->r_ptr,
935                 //                              state->call);
936                 //}
937                 tevent_req_nterror(req, error);
938                 return tevent_req_post(req, ev);
939         }
940
941         /*
942          * Note: the first struct member is always
943          * 'uint32_t count;'
944          */
945         count = (const uint32_t *)chunk_ptr;
946
947         state->is_last_chunk = false;
948         if (*count == 0) {
949                 state->is_last_chunk = true;
950         }
951
952         if (call_state->in_pipe_idx >= call_state->params->in.num_pipes) {
953                 is_last_pipe = true;
954         }
955
956         if (is_last_pipe && state->is_last_chunk) {
957                 call_state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
958         } else {
959                 /*
960                  * push alignment for the next pipe chunk
961                  */
962                 ndr_err = ndr_push_align(state->push, 5);
963                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
964                         NTSTATUS error;
965                         error = ndr_map_error2ntstatus(ndr_err);
966                         tevent_req_nterror(req, error);
967                         return tevent_req_post(req, ev);
968                 }
969         }
970
971         /* retrieve the blob - including possible alignment for the next chunk */
972         state->chunk_blob = ndr_push_blob(state->push);
973
974         subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
975                                                         call_state->subreq,
976                                                         call_state->in_flags,
977                                                         state->chunk_blob.data,
978                                                         state->chunk_blob.length);
979         if (tevent_req_nomem(subreq, req)) {
980                 return tevent_req_post(req, ev);
981         }
982         tevent_req_set_callback(subreq,
983                                 dcerpc_binding_handle_call_params_push_done,
984                                 req);
985
986         return req;
987 }
988
989 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq)
990 {
991         struct tevent_req *req =
992                 tevent_req_callback_data(subreq,
993                 struct tevent_req);
994         struct dcerpc_binding_handle_call_params_push_state *state =
995                 tevent_req_data(req,
996                 struct dcerpc_binding_handle_call_params_push_state);
997         struct dcerpc_binding_handle_call_params_pipe *pp =
998                 dcerpc_pipe_handle_data(state->p,
999                 struct dcerpc_binding_handle_call_params_pipe);
1000         NTSTATUS status;
1001
1002         status = dcerpc_binding_handle_raw_call_in_recv(subreq);
1003         TALLOC_FREE(subreq);
1004         TALLOC_FREE(state->push);
1005         if (tevent_req_nterror(req, status)) {
1006                 return;
1007         }
1008
1009         talloc_set_destructor(state, NULL);
1010
1011         if (!state->is_last_chunk) {
1012                 tevent_req_done(req);
1013                 return;
1014         }
1015
1016         tevent_req_defer_callback(req, state->ev);
1017         tevent_req_done(req);
1018         dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
1019 }
1020
1021 static NTSTATUS dcerpc_binding_handle_call_params_push_recv(struct tevent_req *req)
1022 {
1023         return tevent_req_simple_recv_ntstatus(req);
1024 }
1025
1026 struct dcerpc_binding_handle_call_params_pull_state {
1027         struct tevent_context *ev;
1028         struct dcerpc_pipe_handle *p;
1029         void *chunk_mem;
1030         void *chunk_ptr;
1031 };
1032
1033 static int dcerpc_binding_handle_call_params_pull_state_destructor(
1034         struct dcerpc_binding_handle_call_params_pull_state *state)
1035 {
1036         struct dcerpc_binding_handle_call_params_pipe *pp =
1037                 dcerpc_pipe_handle_data(state->p,
1038                 struct dcerpc_binding_handle_call_params_pipe);
1039         struct dcerpc_binding_handle_call_params_state *call_state =
1040                 tevent_req_data(pp->call_req,
1041                 struct dcerpc_binding_handle_call_params_state);
1042
1043         pp->pull_req = NULL;
1044
1045         dcerpc_pipe_handle_connection_disconnect(call_state->pc);
1046         call_state->pc = NULL;
1047         call_state->call_pipe = NULL;
1048         return 0;
1049 }
1050
1051 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req);
1052
1053 static struct tevent_req *dcerpc_binding_handle_call_params_pull_send(TALLOC_CTX *mem_ctx,
1054                                         struct tevent_context *ev,
1055                                         struct dcerpc_pipe_handle *p,
1056                                         void *chunk_mem,
1057                                         void *chunk_ptr)
1058 {
1059         struct dcerpc_binding_handle_call_params_pipe *pp =
1060                 dcerpc_pipe_handle_data(p,
1061                 struct dcerpc_binding_handle_call_params_pipe);
1062         struct tevent_req *req;
1063         struct dcerpc_binding_handle_call_params_pull_state *state;
1064
1065         req = tevent_req_create(mem_ctx, &state,
1066                                 struct dcerpc_binding_handle_call_params_pull_state);
1067         if (req == NULL) {
1068                 return NULL;
1069         }
1070         state->ev = ev;
1071         state->p = p;
1072         state->chunk_mem = chunk_mem;
1073         state->chunk_ptr = chunk_ptr;
1074
1075         dcerpc_binding_handle_call_params_pull_notify(req);
1076         if (!tevent_req_is_in_progress(req)) {
1077                 return tevent_req_post(req, ev);
1078         }
1079
1080         talloc_set_destructor(state,
1081                               dcerpc_binding_handle_call_params_pull_state_destructor);
1082         pp->pull_req = req;
1083
1084         return req;
1085 }
1086
1087 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req)
1088 {
1089         struct dcerpc_binding_handle_call_params_pull_state *state =
1090                 tevent_req_data(req,
1091                 struct dcerpc_binding_handle_call_params_pull_state);
1092         struct dcerpc_binding_handle_call_params_pipe *pp =
1093                 dcerpc_pipe_handle_data(state->p,
1094                 struct dcerpc_binding_handle_call_params_pipe);
1095         struct dcerpc_binding_handle_call_params_state *call_state =
1096                 tevent_req_data(pp->call_req,
1097                 struct dcerpc_binding_handle_call_params_state);
1098         enum ndr_err_code ndr_err;
1099         const uint32_t *count = NULL;
1100
1101         if (call_state->pull == NULL) {
1102                 return;
1103         }
1104
1105         if (call_state->pull->data_size == 0) {
1106                 return;
1107         }
1108
1109         call_state->pull->current_mem_ctx = state->chunk_mem;
1110
1111         /* pull the structure from the blob */
1112         ndr_err = call_state->call_pipe->ndr_pull(call_state->pull,
1113                                                   NDR_SCALARS|NDR_BUFFERS,
1114                                                   state->chunk_ptr);
1115         if (ndr_err == NDR_ERR_INCOMPLETE_BUFFER) {
1116                 return;
1117         }
1118         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1119                 NTSTATUS error;
1120                 error = ndr_map_error2ntstatus(ndr_err);
1121                 //if (h->ops->ndr_pull_failed) {
1122                 //      h->ops->ndr_pull_failed(h, error,
1123                 //                              &state->response,
1124                 //                              state->call);
1125                 //}
1126                 tevent_req_nterror(req, error);
1127                 return;
1128         }
1129
1130         //if (h->ops->do_ndr_print) {
1131         //      h->ops->do_ndr_print(h, NDR_OUT,
1132         //                           state->params->r_ptr, state->call);
1133         //}
1134
1135         //if (h->ops->ndr_validate_out) {
1136         //      error = h->ops->ndr_validate_out(h,
1137         //                                       state->pull,
1138         //                                       state->params->r_ptr,
1139         //                                       state->call);
1140         //      if (!NT_STATUS_IS_OK(error)) {
1141         //              tevent_req_nterror(req, error);
1142         //              return;
1143         //      }
1144         //}
1145
1146         //ndr_err = ndr_pull_pop(call_state->pull);
1147         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1148                 NTSTATUS error;
1149                 error = ndr_map_error2ntstatus(ndr_err);
1150                 tevent_req_nterror(req, error);
1151                 return;
1152         }
1153
1154         pp->pull_req = NULL;
1155         talloc_set_destructor(state, NULL);
1156
1157         /*
1158          * Note: the first struct member is always
1159          * 'uint32_t count;'
1160          */
1161         count = (const uint32_t *)state->chunk_ptr;
1162
1163         if (*count != 0) {
1164                 tevent_req_done(req);
1165                 return;
1166         }
1167
1168         tevent_req_defer_callback(req, state->ev);
1169         tevent_req_done(req);
1170         dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
1171
1172 }
1173
1174 static NTSTATUS dcerpc_binding_handle_call_params_pull_recv(struct tevent_req *req)
1175 {
1176         return tevent_req_simple_recv_ntstatus(req);
1177 }
1178
1179 static struct dcerpc_pipe_handle_ops dcerpc_binding_handle_call_params_pipe_ops = {
1180         .name = "dcerpc_binding_handle_call_params_pipe",
1181
1182         .chunk_push_send = dcerpc_binding_handle_call_params_push_send,
1183         .chunk_push_recv = dcerpc_binding_handle_call_params_push_recv,
1184
1185         .chunk_pull_send = dcerpc_binding_handle_call_params_pull_send,
1186         .chunk_pull_recv = dcerpc_binding_handle_call_params_pull_recv,
1187 };
1188
1189 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req)
1190 {
1191         struct dcerpc_binding_handle_call_params_state *call_state =
1192                 tevent_req_data(call_req,
1193                 struct dcerpc_binding_handle_call_params_state);
1194         struct dcerpc_binding_handle_call_params_pipe *pp;
1195
1196         call_state->ph = dcerpc_pipe_handle_create(call_state,
1197                                 &dcerpc_binding_handle_call_params_pipe_ops,
1198                                 &pp,
1199                                 struct dcerpc_binding_handle_call_params_pipe);
1200         if (tevent_req_nomem(call_state->ph, call_req)) {
1201                 return;
1202         }
1203
1204         pp->call_req = call_req;
1205 };
1206
1207 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p)
1208 {
1209         struct dcerpc_binding_handle_call_params_pipe *pp =
1210                 dcerpc_pipe_handle_data(p,
1211                 struct dcerpc_binding_handle_call_params_pipe);
1212
1213         if (pp->pull_req == NULL) {
1214                 return;
1215         }
1216
1217         dcerpc_binding_handle_call_params_pull_notify(pp->pull_req);
1218 }
1219
1220 struct dcerpc_binding_handle_call_state {
1221         struct dcerpc_binding_handle_call_params params;
1222 };
1223
1224 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
1225
1226 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
1227                                         struct tevent_context *ev,
1228                                         struct dcerpc_binding_handle *h,
1229                                         const struct GUID *object,
1230                                         const struct ndr_interface_table *table,
1231                                         uint32_t opnum,
1232                                         TALLOC_CTX *r_mem,
1233                                         void *r_ptr)
1234 {
1235         struct tevent_req *req;
1236         struct dcerpc_binding_handle_call_state *state;
1237         struct tevent_req *subreq;
1238
1239         req = tevent_req_create(mem_ctx, &state,
1240                                 struct dcerpc_binding_handle_call_state);
1241         if (req == NULL) {
1242                 return NULL;
1243         }
1244
1245         state->params.r_mem = r_mem;
1246         state->params.r_ptr = r_ptr;
1247
1248         subreq = dcerpc_binding_handle_call_params_send(state, ev, h,
1249                                                         object, table, opnum,
1250                                                         &state->params);
1251         if (tevent_req_nomem(subreq, req)) {
1252                 return tevent_req_post(req, ev);
1253         }
1254         tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
1255
1256         return req;
1257 }
1258
1259 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
1260 {
1261         struct tevent_req *req = tevent_req_callback_data(subreq,
1262                                  struct tevent_req);
1263         NTSTATUS error;
1264
1265         error = dcerpc_binding_handle_call_params_recv(subreq);
1266         TALLOC_FREE(subreq);
1267         if (tevent_req_nterror(req, error)) {
1268                 return;
1269         }
1270
1271         tevent_req_done(req);
1272 }
1273
1274 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
1275 {
1276         return tevent_req_simple_recv_ntstatus(req);
1277 }
1278
1279 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
1280                                     const struct GUID *object,
1281                                     const struct ndr_interface_table *table,
1282                                     uint32_t opnum,
1283                                     TALLOC_CTX *r_mem,
1284                                     void *r_ptr)
1285 {
1286         TALLOC_CTX *frame = talloc_stackframe();
1287         struct tevent_context *ev;
1288         struct tevent_req *subreq;
1289         struct dcerpc_binding_handle_call_params params;
1290         NTSTATUS status = NT_STATUS_NO_MEMORY;
1291
1292         /*
1293          * TODO: allow only one sync call
1294          */
1295
1296         if (h->sync_ev) {
1297                 ev = h->sync_ev;
1298         } else {
1299                 ev = samba_tevent_context_init(frame);
1300         }
1301         if (ev == NULL) {
1302                 goto fail;
1303         }
1304
1305         ZERO_STRUCT(params);
1306         params.r_mem = r_mem;
1307         params.r_ptr = r_ptr;
1308
1309         subreq = dcerpc_binding_handle_call_params_send(frame, ev, h,
1310                                                         object, table, opnum,
1311                                                         &params);
1312         if (subreq == NULL) {
1313                 goto fail;
1314         }
1315
1316         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
1317                 goto fail;
1318         }
1319
1320         status = dcerpc_binding_handle_call_params_recv(subreq);
1321 fail:
1322         TALLOC_FREE(frame);
1323         return status;
1324 }