TODO cleanup incomplete_buffer librpc/rpc/binding_handle.c
[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 tevent_context *ev;
457         struct dcerpc_binding_handle *h;
458         const struct ndr_interface_call *call;
459         struct dcerpc_binding_handle_call_params *params;
460         uint32_t in_flags;
461         struct ndr_push *push;
462         DATA_BLOB request;
463         struct tevent_req *subreq;
464         DATA_BLOB response;
465         struct ndr_pull *pull;
466
467         struct dcerpc_pipe_handle *ph;
468         struct dcerpc_pipe_handle_connection *pc;
469         const struct ndr_interface_call_pipe *call_pipe;
470         uint32_t in_pipe_idx;
471         uint32_t out_pipe_idx;
472 };
473
474 static void dcerpc_binding_handle_call_params_cleanup(struct tevent_req *req);
475 static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq);
476 static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req);
477 static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq);
478 static void dcerpc_binding_handle_call_params_response(struct tevent_req *req);
479 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req);
480 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p);
481
482 struct tevent_req *dcerpc_binding_handle_call_params_send(TALLOC_CTX *mem_ctx,
483                                 struct tevent_context *ev,
484                                 struct dcerpc_binding_handle *h,
485                                 const struct GUID *object,
486                                 const struct ndr_interface_table *table,
487                                 uint32_t opnum,
488                                 struct dcerpc_binding_handle_call_params *params)
489 {
490         struct tevent_req *req;
491         struct dcerpc_binding_handle_call_params_state *state;
492         enum ndr_err_code ndr_err;
493
494         req = tevent_req_create(mem_ctx, &state,
495                                 struct dcerpc_binding_handle_call_params_state);
496         if (req == NULL) {
497                 return NULL;
498         }
499
500         if (table != h->table) {
501                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
502                 return tevent_req_post(req, ev);
503         }
504
505         if (opnum >= table->num_calls) {
506                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
507                 return tevent_req_post(req, ev);
508         }
509
510         state->ev = ev;
511         state->h = h;
512         state->call = &table->calls[opnum];
513         state->params = params;
514
515         if (params->in.num_pipes != state->call->in_pipes.num_pipes) {
516                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
517                 return tevent_req_post(req, ev);
518         }
519
520         if (params->out.num_pipes != state->call->out_pipes.num_pipes) {
521                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
522                 return tevent_req_post(req, ev);
523         }
524
525         tevent_req_defer_callback(req, ev);
526
527         /* setup for a ndr_push_* call */
528         state->push = ndr_push_init_ctx(state);
529         if (tevent_req_nomem(state->push, req)) {
530                 return tevent_req_post(req, ev);
531         }
532
533         if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
534                 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
535         }
536
537         if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
538                 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
539                 state->in_flags |= LIBNDR_FLAG_BIGENDIAN;
540         }
541
542         if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
543                 state->push->flags |= LIBNDR_FLAG_NDR64;
544         }
545
546         if (h->ops->do_ndr_print) {
547                 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
548                                      state->params->r_ptr, state->call);
549         }
550
551         /* push the structure into a blob */
552         ndr_err = state->call->ndr_push(state->push, NDR_IN, state->params->r_ptr);
553         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
554                 NTSTATUS error;
555                 error = ndr_map_error2ntstatus(ndr_err);
556                 if (h->ops->ndr_push_failed) {
557                         h->ops->ndr_push_failed(h, error,
558                                                 state->params->r_ptr,
559                                                 state->call);
560                 }
561                 tevent_req_nterror(req, error);
562                 return tevent_req_post(req, ev);
563         }
564
565         /* retrieve the blob */
566         state->request = ndr_push_blob(state->push);
567
568         if (h->ops->ndr_validate_in) {
569                 NTSTATUS error;
570                 error = h->ops->ndr_validate_in(h, state,
571                                                 &state->request,
572                                                 state->call);
573                 if (!NT_STATUS_IS_OK(error)) {
574                         tevent_req_nterror(req, error);
575                         return tevent_req_post(req, ev);
576                 }
577         }
578
579         if (params->in.num_pipes != 0) {
580                 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
581
582                 /*
583                  * push alignment for the next pipe chunk
584                  */
585                 ndr_err = ndr_push_align(state->push, 5);
586                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
587                         NTSTATUS error;
588                         error = ndr_map_error2ntstatus(ndr_err);
589                         tevent_req_nterror(req, error);
590                         return tevent_req_post(req, ev);
591                 }
592         }
593
594         if (params->out.num_pipes != 0) {
595                 /*
596                  * even if we only have output pipes we need to indicate that
597                  * we want to get incomplete results
598                  */
599                 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
600         }
601
602         if (state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
603                 dcerpc_binding_handle_call_params_pipe_setup(req);
604                 if (!tevent_req_is_in_progress(req)) {
605                         return tevent_req_post(req, ev);
606                 }
607         }
608
609         /* retrieve the blob - including possible pipe chunk alignment */
610         state->request = ndr_push_blob(state->push);
611
612         state->subreq = dcerpc_binding_handle_raw_call_send(state, ev,
613                                                 h, object, opnum,
614                                                 state->in_flags,
615                                                 state->request.data,
616                                                 state->request.length);
617         if (tevent_req_nomem(state->subreq, req)) {
618                 return tevent_req_post(req, ev);
619         }
620         tevent_req_set_callback(state->subreq,
621                                 dcerpc_binding_handle_call_params_done,
622                                 req);
623
624         if (!(state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
625                 /*
626                  * we didn't ask for any pipes
627                  *
628                  * Indicate that all pipes are done.
629                  */
630                 state->in_pipe_idx = UINT32_MAX;
631                 state->out_pipe_idx = UINT32_MAX;
632                 return req;
633         }
634
635         /*
636          * If the subreq is already finished, the backend
637          * may not support LIBNDR_FLAG_INCOMPLETE_BUFFER
638          */
639         if (!tevent_req_is_in_progress(state->subreq)) {
640                 return req;
641         }
642
643         dcerpc_binding_handle_call_params_next_pipe(req);
644         if (!tevent_req_is_in_progress(req)) {
645                 return tevent_req_post(req, ev);
646         }
647
648         if (state->params->in.num_pipes == 0) {
649                 struct tevent_req *subreq;
650
651                 /*
652                  * We have only out pipes,
653                  * so indicate that we're done with sending in_data.
654                  */
655                 state->in_pipe_idx = UINT32_MAX;
656                 state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
657                 subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
658                                                                 state->subreq,
659                                                                 state->in_flags,
660                                                                 NULL, /* in_data */
661                                                                 0); /* in_length */
662                 if (tevent_req_nomem(subreq, req)) {
663                         return tevent_req_post(req, ev);
664                 }
665                 tevent_req_set_callback(subreq,
666                                         dcerpc_binding_handle_call_params_in_done,
667                                         req);
668                 return req;
669         }
670
671         return req;
672 }
673
674 static void dcerpc_binding_handle_call_params_cleanup(struct tevent_req *req)
675 {
676         struct dcerpc_binding_handle_call_params_state *state =
677                 tevent_req_data(req,
678                 struct dcerpc_binding_handle_call_params_state);
679
680         dcerpc_pipe_handle_connection_disconnect(state->pc);
681         state->pc = NULL;
682         state->call_pipe = NULL;
683
684         tevent_req_post(req, state->ev);
685 }
686
687 static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq)
688 {
689         struct tevent_req *req = tevent_req_callback_data(subreq,
690                                  struct tevent_req);
691         NTSTATUS error;
692
693         error = dcerpc_binding_handle_raw_call_in_recv(subreq);
694         TALLOC_FREE(subreq);
695         if (tevent_req_nterror(req, error)) {
696                 dcerpc_binding_handle_call_params_cleanup(req);
697                 return;
698         }
699
700         /*
701          * nothing to do here
702          */
703 }
704
705 static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req)
706 {
707         struct dcerpc_binding_handle_call_params_state *state =
708                 tevent_req_data(req,
709                 struct dcerpc_binding_handle_call_params_state);
710         struct dcerpc_binding_handle_call_params *params = state->params;
711         bool ok;
712
713         dcerpc_pipe_handle_connection_disconnect(state->pc);
714         state->pc = NULL;
715         state->call_pipe = NULL;
716
717         if (state->in_pipe_idx < params->in.num_pipes) {
718                 uint32_t idx = state->in_pipe_idx++;
719
720                 state->pc = params->in.pipes[idx];
721                 state->call_pipe = &state->call->in_pipes.pipes[idx];
722
723                 ok = dcerpc_pipe_handle_connection_push_connect(state->pc,
724                                         state->call_pipe->chunk_struct_name,
725                                         state->call_pipe->chunk_struct_size,
726                                         state->ph);
727                 if (!ok) {
728                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
729                         dcerpc_binding_handle_call_params_cleanup(req);
730                         return;
731                 }
732
733                 return;
734         }
735         state->in_pipe_idx = UINT32_MAX;
736
737         if (state->out_pipe_idx < params->out.num_pipes) {
738                 uint32_t idx = state->out_pipe_idx++;
739
740                 state->pc = params->out.pipes[idx];
741                 state->call_pipe = &state->call->out_pipes.pipes[idx];
742
743                 ok = dcerpc_pipe_handle_connection_pull_connect(state->pc,
744                                         state->call_pipe->chunk_struct_name,
745                                         state->call_pipe->chunk_struct_size,
746                                         state->ph);
747                 if (!ok) {
748                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
749                         dcerpc_binding_handle_call_params_cleanup(req);
750                         return;
751                 }
752
753                 return;
754         }
755         state->out_pipe_idx = UINT32_MAX;
756
757         if (state->pull == NULL) {
758                 return;
759         }
760
761         if (state->pull->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
762                 return;
763         }
764
765         dcerpc_binding_handle_call_params_response(req);
766 }
767
768 static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq)
769 {
770         struct tevent_req *req = tevent_req_callback_data(subreq,
771                                  struct tevent_req);
772         struct dcerpc_binding_handle_call_params_state *state =
773                 tevent_req_data(req,
774                 struct dcerpc_binding_handle_call_params_state);
775         struct dcerpc_binding_handle *h = state->h;
776         NTSTATUS error;
777         uint32_t out_flags = 0;
778         enum ndr_err_code ndr_err;
779
780         error = dcerpc_binding_handle_raw_call_recv(subreq, state,
781                                                     &state->response.data,
782                                                     &state->response.length,
783                                                     &out_flags);
784         subreq = NULL;
785         if (!NT_STATUS_IS_OK(error)) {
786                 TALLOC_FREE(state->subreq);
787                 tevent_req_nterror(req, error);
788                 dcerpc_binding_handle_call_params_cleanup(req);
789                 return;
790         }
791
792         if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
793                 TALLOC_FREE(state->subreq);
794         }
795
796         if (state->in_pipe_idx != UINT32_MAX) {
797                 /*
798                  * we haven't send all data yet,
799                  * this is a protocol error
800                  */
801                 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
802                 dcerpc_binding_handle_call_params_cleanup(req);
803                 return;
804         }
805
806         if (state->pull == NULL) {
807                 state->pull = ndr_pull_init_blob(&state->response, state);
808                 if (tevent_req_nomem(state->pull, req)) {
809                         dcerpc_binding_handle_call_params_cleanup(req);
810                         return;
811                 }
812                 state->pull->flags = state->push->flags;
813
814                 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
815                         state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
816                 } else {
817                         state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
818                 }
819
820                 if (out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
821                         state->pull->flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
822                 }
823         } else {
824                 if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
825                         state->pull->flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
826                 }
827
828                 ndr_err = ndr_pull_append(state->pull,
829                                           &state->response);
830                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
831                         error = ndr_map_error2ntstatus(ndr_err);
832                         if (h->ops->ndr_pull_failed) {
833                                 h->ops->ndr_pull_failed(h, error,
834                                                         &state->response,
835                                                         state->call);
836                         }
837                         tevent_req_nterror(req, error);
838                         dcerpc_binding_handle_call_params_cleanup(req);
839                         return;
840                 }
841         }
842
843         if (state->out_pipe_idx != UINT32_MAX) {
844                 dcerpc_binding_handle_call_params_pipe_notify(state->ph);
845                 return;
846         }
847
848         dcerpc_binding_handle_call_params_response(req);
849 }
850
851 static void dcerpc_binding_handle_call_params_response(struct tevent_req *req)
852 {
853         struct dcerpc_binding_handle_call_params_state *state =
854                 tevent_req_data(req,
855                 struct dcerpc_binding_handle_call_params_state);
856         struct dcerpc_binding_handle *h = state->h;
857         NTSTATUS error;
858         enum ndr_err_code ndr_err;
859
860         state->pull->current_mem_ctx = state->params->r_mem;
861
862         /* pull the structure from the blob */
863         ndr_err = state->call->ndr_pull(state->pull, NDR_OUT,
864                                         state->params->r_ptr);
865         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
866                 error = ndr_map_error2ntstatus(ndr_err);
867                 if (h->ops->ndr_pull_failed) {
868                         h->ops->ndr_pull_failed(h, error,
869                                                 &state->response,
870                                                 state->call);
871                 }
872                 tevent_req_nterror(req, error);
873                 dcerpc_binding_handle_call_params_cleanup(req);
874                 return;
875         }
876
877         if (h->ops->do_ndr_print) {
878                 h->ops->do_ndr_print(h, NDR_OUT,
879                                      state->params->r_ptr, state->call);
880         }
881
882         if (h->ops->ndr_validate_out) {
883                 error = h->ops->ndr_validate_out(h,
884                                                  state->pull,
885                                                  state->params->r_ptr,
886                                                  state->call);
887                 if (!NT_STATUS_IS_OK(error)) {
888                         tevent_req_nterror(req, error);
889                         dcerpc_binding_handle_call_params_cleanup(req);
890                         return;
891                 }
892         }
893
894         tevent_req_done(req);
895 }
896
897 NTSTATUS dcerpc_binding_handle_call_params_recv(struct tevent_req *req)
898 {
899         return tevent_req_simple_recv_ntstatus(req);
900 }
901
902 struct dcerpc_binding_handle_call_params_pipe {
903         struct tevent_req *call_req;
904         struct tevent_req *pull_req;
905 };
906
907 struct dcerpc_binding_handle_call_params_push_state {
908         struct tevent_context *ev;
909         struct dcerpc_pipe_handle *p;
910         struct ndr_push *push;
911         DATA_BLOB chunk_blob;
912         bool is_last_chunk;
913 };
914
915 static int dcerpc_binding_handle_call_params_push_state_destructor(
916         struct dcerpc_binding_handle_call_params_push_state *state)
917 {
918         struct dcerpc_binding_handle_call_params_pipe *pp =
919                 dcerpc_pipe_handle_data(state->p,
920                 struct dcerpc_binding_handle_call_params_pipe);
921
922         if (!state->is_last_chunk) {
923                 return 0;
924         }
925
926         dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
927         return 0;
928 }
929
930 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq);
931
932 static struct tevent_req *dcerpc_binding_handle_call_params_push_send(TALLOC_CTX *mem_ctx,
933                                         struct tevent_context *ev,
934                                         struct dcerpc_pipe_handle *p,
935                                         const void *chunk_ptr)
936 {
937         struct dcerpc_binding_handle_call_params_pipe *pp =
938                 dcerpc_pipe_handle_data(p,
939                 struct dcerpc_binding_handle_call_params_pipe);
940         struct dcerpc_binding_handle_call_params_state *call_state =
941                 tevent_req_data(pp->call_req,
942                 struct dcerpc_binding_handle_call_params_state);
943         struct tevent_req *req;
944         struct dcerpc_binding_handle_call_params_push_state *state;
945         struct tevent_req *subreq;
946         enum ndr_err_code ndr_err;
947         const uint32_t *count = NULL;
948         bool is_last_pipe = false;
949
950         req = tevent_req_create(mem_ctx, &state,
951                                 struct dcerpc_binding_handle_call_params_push_state);
952         if (req == NULL) {
953                 return NULL;
954         }
955         state->ev = ev;
956         state->p = p;
957         state->is_last_chunk = true;
958
959         tevent_req_defer_callback(req, state->ev);
960
961         talloc_set_destructor(state,
962                               dcerpc_binding_handle_call_params_push_state_destructor);
963
964         /* setup for a ndr_push_* call */
965         state->push = ndr_push_init_ctx(state);
966         if (tevent_req_nomem(state->push, req)) {
967                 return tevent_req_post(req, ev);
968         }
969
970         state->push->flags = call_state->push->flags;
971
972         //if (h->ops->do_ndr_print) {
973         //      h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
974         //                           state->params->r_ptr, state->call);
975         //}
976
977         /* push the structure into a blob */
978         ndr_err = call_state->call_pipe->ndr_push(state->push,
979                                                   NDR_SCALARS|NDR_BUFFERS,
980                                                   chunk_ptr);
981         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
982                 NTSTATUS error;
983                 error = ndr_map_error2ntstatus(ndr_err);
984                 //if (h->ops->ndr_push_failed) {
985                 //      h->ops->ndr_push_failed(h, error,
986                 //                              state->params->r_ptr,
987                 //                              state->call);
988                 //}
989                 tevent_req_nterror(req, error);
990                 return tevent_req_post(req, ev);
991         }
992
993         /*
994          * Note: the first struct member is always
995          * 'uint32_t count;'
996          */
997         count = (const uint32_t *)chunk_ptr;
998
999         state->is_last_chunk = false;
1000         if (*count == 0) {
1001                 state->is_last_chunk = true;
1002         }
1003
1004         if (call_state->in_pipe_idx >= call_state->params->in.num_pipes) {
1005                 is_last_pipe = true;
1006         }
1007
1008         if (is_last_pipe && state->is_last_chunk) {
1009                 call_state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
1010         } else {
1011                 /*
1012                  * push alignment for the next pipe chunk
1013                  */
1014                 ndr_err = ndr_push_align(state->push, 5);
1015                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1016                         NTSTATUS error;
1017                         error = ndr_map_error2ntstatus(ndr_err);
1018                         tevent_req_nterror(req, error);
1019                         return tevent_req_post(req, ev);
1020                 }
1021         }
1022
1023         /* retrieve the blob - including possible alignment for the next chunk */
1024         state->chunk_blob = ndr_push_blob(state->push);
1025
1026         subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
1027                                                         call_state->subreq,
1028                                                         call_state->in_flags,
1029                                                         state->chunk_blob.data,
1030                                                         state->chunk_blob.length);
1031         if (tevent_req_nomem(subreq, req)) {
1032                 return tevent_req_post(req, ev);
1033         }
1034         tevent_req_set_callback(subreq,
1035                                 dcerpc_binding_handle_call_params_push_done,
1036                                 req);
1037
1038         return req;
1039 }
1040
1041 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq)
1042 {
1043         struct tevent_req *req =
1044                 tevent_req_callback_data(subreq,
1045                 struct tevent_req);
1046         struct dcerpc_binding_handle_call_params_push_state *state =
1047                 tevent_req_data(req,
1048                 struct dcerpc_binding_handle_call_params_push_state);
1049         NTSTATUS status;
1050
1051         status = dcerpc_binding_handle_raw_call_in_recv(subreq);
1052         TALLOC_FREE(subreq);
1053         TALLOC_FREE(state->push);
1054         if (tevent_req_nterror(req, status)) {
1055                 return;
1056         }
1057
1058         tevent_req_done(req);
1059 }
1060
1061 static NTSTATUS dcerpc_binding_handle_call_params_push_recv(struct tevent_req *req)
1062 {
1063         return tevent_req_simple_recv_ntstatus(req);
1064 }
1065
1066 struct dcerpc_binding_handle_call_params_pull_state {
1067         struct tevent_context *ev;
1068         struct dcerpc_pipe_handle *p;
1069         void *chunk_mem;
1070         void *chunk_ptr;
1071         bool is_last_chunk;
1072 };
1073
1074 static int dcerpc_binding_handle_call_params_pull_state_destructor(
1075         struct dcerpc_binding_handle_call_params_pull_state *state)
1076 {
1077         struct dcerpc_binding_handle_call_params_pipe *pp =
1078                 dcerpc_pipe_handle_data(state->p,
1079                 struct dcerpc_binding_handle_call_params_pipe);
1080
1081         pp->pull_req = NULL;
1082
1083         if (!state->is_last_chunk) {
1084                 return 0;
1085         }
1086
1087         dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
1088         return 0;
1089 }
1090
1091 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req);
1092
1093 static struct tevent_req *dcerpc_binding_handle_call_params_pull_send(TALLOC_CTX *mem_ctx,
1094                                         struct tevent_context *ev,
1095                                         struct dcerpc_pipe_handle *p,
1096                                         void *chunk_mem,
1097                                         void *chunk_ptr)
1098 {
1099         struct dcerpc_binding_handle_call_params_pipe *pp =
1100                 dcerpc_pipe_handle_data(p,
1101                 struct dcerpc_binding_handle_call_params_pipe);
1102         struct tevent_req *req;
1103         struct dcerpc_binding_handle_call_params_pull_state *state;
1104
1105         req = tevent_req_create(mem_ctx, &state,
1106                                 struct dcerpc_binding_handle_call_params_pull_state);
1107         if (req == NULL) {
1108                 return NULL;
1109         }
1110         state->ev = ev;
1111         state->p = p;
1112         state->chunk_mem = chunk_mem;
1113         state->chunk_ptr = chunk_ptr;
1114         state->is_last_chunk = true;
1115
1116         tevent_req_defer_callback(req, state->ev);
1117
1118         talloc_set_destructor(state,
1119                               dcerpc_binding_handle_call_params_pull_state_destructor);
1120         pp->pull_req = req;
1121
1122         dcerpc_binding_handle_call_params_pull_notify(req);
1123         if (!tevent_req_is_in_progress(req)) {
1124                 return tevent_req_post(req, ev);
1125         }
1126
1127         return req;
1128 }
1129
1130 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req)
1131 {
1132         struct dcerpc_binding_handle_call_params_pull_state *state =
1133                 tevent_req_data(req,
1134                 struct dcerpc_binding_handle_call_params_pull_state);
1135         struct dcerpc_binding_handle_call_params_pipe *pp =
1136                 dcerpc_pipe_handle_data(state->p,
1137                 struct dcerpc_binding_handle_call_params_pipe);
1138         struct dcerpc_binding_handle_call_params_state *call_state =
1139                 tevent_req_data(pp->call_req,
1140                 struct dcerpc_binding_handle_call_params_state);
1141         enum ndr_err_code ndr_err;
1142         const uint32_t *count = NULL;
1143         uint32_t saved_offset;
1144         size_t saved_ndr_blocks;
1145         size_t saved_mem_blocks;
1146
1147         if (call_state->pull == NULL) {
1148                 return;
1149         }
1150
1151         if (call_state->pull->data_size == 0) {
1152                 return;
1153         }
1154
1155         /* pull the structure from the blob */
1156         saved_offset = call_state->pull->offset;
1157         saved_ndr_blocks = talloc_total_blocks(call_state->pull);
1158         saved_mem_blocks = talloc_total_blocks(state->chunk_mem);
1159
1160         call_state->pull->current_mem_ctx = state->chunk_mem;
1161         ndr_err = call_state->call_pipe->ndr_pull(call_state->pull,
1162                                                   NDR_SCALARS|NDR_BUFFERS,
1163                                                   state->chunk_ptr);
1164         if (ndr_err == NDR_ERR_INCOMPLETE_BUFFER) {
1165                 SMB_ASSERT(saved_mem_blocks == 1);
1166                 SMB_ASSERT(saved_ndr_blocks == talloc_total_blocks(call_state->pull));
1167                 talloc_free_children(state->chunk_mem);
1168                 call_state->pull->offset = saved_offset;
1169                 return;
1170         }
1171         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1172                 NTSTATUS error;
1173                 error = ndr_map_error2ntstatus(ndr_err);
1174                 //if (h->ops->ndr_pull_failed) {
1175                 //      h->ops->ndr_pull_failed(h, error,
1176                 //                              &state->response,
1177                 //                              state->call);
1178                 //}
1179                 tevent_req_nterror(req, error);
1180                 return;
1181         }
1182
1183         //if (h->ops->do_ndr_print) {
1184         //      h->ops->do_ndr_print(h, NDR_OUT,
1185         //                           state->params->r_ptr, state->call);
1186         //}
1187
1188         //if (h->ops->ndr_validate_out) {
1189         //      error = h->ops->ndr_validate_out(h,
1190         //                                       state->pull,
1191         //                                       state->params->r_ptr,
1192         //                                       state->call);
1193         //      if (!NT_STATUS_IS_OK(error)) {
1194         //              tevent_req_nterror(req, error);
1195         //              return;
1196         //      }
1197         //}
1198
1199         ndr_err = ndr_pull_pop(call_state->pull);
1200         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1201                 NTSTATUS error;
1202                 error = ndr_map_error2ntstatus(ndr_err);
1203                 tevent_req_nterror(req, error);
1204                 return;
1205         }
1206
1207         /*
1208          * Note: the first struct member is always
1209          * 'uint32_t count;'
1210          */
1211         count = (const uint32_t *)state->chunk_ptr;
1212
1213         if (*count != 0) {
1214                 state->is_last_chunk = false;
1215                 tevent_req_done(req);
1216                 return;
1217         }
1218
1219         state->is_last_chunk = true;
1220         tevent_req_done(req);
1221
1222 }
1223
1224 static NTSTATUS dcerpc_binding_handle_call_params_pull_recv(struct tevent_req *req)
1225 {
1226         return tevent_req_simple_recv_ntstatus(req);
1227 }
1228
1229 static struct dcerpc_pipe_handle_ops dcerpc_binding_handle_call_params_pipe_ops = {
1230         .name = "dcerpc_binding_handle_call_params_pipe",
1231
1232         .chunk_push_send = dcerpc_binding_handle_call_params_push_send,
1233         .chunk_push_recv = dcerpc_binding_handle_call_params_push_recv,
1234
1235         .chunk_pull_send = dcerpc_binding_handle_call_params_pull_send,
1236         .chunk_pull_recv = dcerpc_binding_handle_call_params_pull_recv,
1237 };
1238
1239 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req)
1240 {
1241         struct dcerpc_binding_handle_call_params_state *call_state =
1242                 tevent_req_data(call_req,
1243                 struct dcerpc_binding_handle_call_params_state);
1244         struct dcerpc_binding_handle_call_params_pipe *pp;
1245
1246         call_state->ph = dcerpc_pipe_handle_create(call_state,
1247                                 &dcerpc_binding_handle_call_params_pipe_ops,
1248                                 &pp,
1249                                 struct dcerpc_binding_handle_call_params_pipe);
1250         if (tevent_req_nomem(call_state->ph, call_req)) {
1251                 return;
1252         }
1253
1254         pp->call_req = call_req;
1255 };
1256
1257 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p)
1258 {
1259         struct dcerpc_binding_handle_call_params_pipe *pp =
1260                 dcerpc_pipe_handle_data(p,
1261                 struct dcerpc_binding_handle_call_params_pipe);
1262
1263         if (pp->pull_req == NULL) {
1264                 return;
1265         }
1266
1267         dcerpc_binding_handle_call_params_pull_notify(pp->pull_req);
1268 }
1269
1270 struct dcerpc_binding_handle_call_state {
1271         struct dcerpc_binding_handle_call_params params;
1272 };
1273
1274 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
1275
1276 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
1277                                         struct tevent_context *ev,
1278                                         struct dcerpc_binding_handle *h,
1279                                         const struct GUID *object,
1280                                         const struct ndr_interface_table *table,
1281                                         uint32_t opnum,
1282                                         TALLOC_CTX *r_mem,
1283                                         void *r_ptr)
1284 {
1285         struct tevent_req *req;
1286         struct dcerpc_binding_handle_call_state *state;
1287         struct tevent_req *subreq;
1288
1289         req = tevent_req_create(mem_ctx, &state,
1290                                 struct dcerpc_binding_handle_call_state);
1291         if (req == NULL) {
1292                 return NULL;
1293         }
1294
1295         state->params.r_mem = r_mem;
1296         state->params.r_ptr = r_ptr;
1297
1298         subreq = dcerpc_binding_handle_call_params_send(state, ev, h,
1299                                                         object, table, opnum,
1300                                                         &state->params);
1301         if (tevent_req_nomem(subreq, req)) {
1302                 return tevent_req_post(req, ev);
1303         }
1304         tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
1305
1306         return req;
1307 }
1308
1309 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
1310 {
1311         struct tevent_req *req = tevent_req_callback_data(subreq,
1312                                  struct tevent_req);
1313         NTSTATUS error;
1314
1315         error = dcerpc_binding_handle_call_params_recv(subreq);
1316         TALLOC_FREE(subreq);
1317         if (tevent_req_nterror(req, error)) {
1318                 return;
1319         }
1320
1321         tevent_req_done(req);
1322 }
1323
1324 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
1325 {
1326         return tevent_req_simple_recv_ntstatus(req);
1327 }
1328
1329 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
1330                                     const struct GUID *object,
1331                                     const struct ndr_interface_table *table,
1332                                     uint32_t opnum,
1333                                     TALLOC_CTX *r_mem,
1334                                     void *r_ptr)
1335 {
1336         TALLOC_CTX *frame = talloc_stackframe();
1337         struct tevent_context *ev;
1338         struct tevent_req *subreq;
1339         struct dcerpc_binding_handle_call_params params;
1340         NTSTATUS status = NT_STATUS_NO_MEMORY;
1341
1342         /*
1343          * TODO: allow only one sync call
1344          */
1345
1346         if (h->sync_ev) {
1347                 ev = h->sync_ev;
1348         } else {
1349                 ev = samba_tevent_context_init(frame);
1350         }
1351         if (ev == NULL) {
1352                 goto fail;
1353         }
1354
1355         ZERO_STRUCT(params);
1356         params.r_mem = r_mem;
1357         params.r_ptr = r_ptr;
1358
1359         subreq = dcerpc_binding_handle_call_params_send(frame, ev, h,
1360                                                         object, table, opnum,
1361                                                         &params);
1362         if (subreq == NULL) {
1363                 goto fail;
1364         }
1365
1366         if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
1367                 goto fail;
1368         }
1369
1370         status = dcerpc_binding_handle_call_params_recv(subreq);
1371 fail:
1372         TALLOC_FREE(frame);
1373         return status;
1374 }