6c5d0ba5980279e71480bdd76315260e6f1d41e6
[metze/samba/wip.git] / source4 / librpc / rpc / dcerpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Jelmer Vernooij 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/rpc/dcerpc_util.h"
30 #include "librpc/rpc/dcerpc_pkt_auth.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32 #include "librpc/gen_ndr/ndr_dcerpc.h"
33 #include "auth/gensec/gensec.h"
34 #include "param/param.h"
35 #include "lib/util/tevent_ntstatus.h"
36 #include "librpc/rpc/rpc_common.h"
37 #include "lib/tsocket/tsocket.h"
38 #include "libcli/smb/tstream_smbXcli_np.h"
39
40
41 enum rpc_request_state {
42         RPC_REQUEST_QUEUED,
43         RPC_REQUEST_PENDING,
44         RPC_REQUEST_DONE
45 };
46
47 /*
48   handle for an async dcerpc request
49 */
50 struct rpc_request {
51         struct rpc_request *next, *prev;
52         struct dcerpc_pipe *p;
53         NTSTATUS status;
54         uint32_t call_id;
55         enum rpc_request_state state;
56         DATA_BLOB payload;
57         uint32_t flags;
58         uint32_t fault_code;
59
60         /* this is used to distinguish bind and alter_context requests
61            from normal requests */
62         void (*recv_handler)(struct rpc_request *conn, 
63                              DATA_BLOB *blob, struct ncacn_packet *pkt);
64
65         const struct GUID *object;
66         uint16_t opnum;
67         DATA_BLOB request_data;
68         bool ignore_timeout;
69         bool wait_for_sync;
70         bool verify_bitmask1;
71         bool verify_pcontext;
72
73         struct {
74                 void (*callback)(struct rpc_request *);
75                 void *private_data;
76         } async;
77 };
78
79 _PUBLIC_ NTSTATUS dcerpc_init(void)
80 {
81         return gensec_init();
82 }
83
84 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
85 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
86 static int dcerpc_req_dequeue(struct rpc_request *req);
87
88 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
89                                                struct dcerpc_pipe *p,
90                                                const struct GUID *object,
91                                                uint16_t opnum,
92                                                DATA_BLOB *stub_data);
93 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
94                                     TALLOC_CTX *mem_ctx,
95                                     DATA_BLOB *stub_data);
96 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
97                                        TALLOC_CTX *mem_ctx,
98                                        DATA_BLOB blob,
99                                        size_t struct_size,
100                                        ndr_push_flags_fn_t ndr_push,
101                                        ndr_pull_flags_fn_t ndr_pull);
102 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
103                                         struct ndr_pull *pull_in,
104                                         void *struct_ptr,
105                                         size_t struct_size,
106                                         ndr_push_flags_fn_t ndr_push,
107                                         ndr_pull_flags_fn_t ndr_pull,
108                                         ndr_print_function_t ndr_print);
109 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
110 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
111                              bool trigger_read);
112 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
113
114 /* destroy a dcerpc connection */
115 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
116 {
117         if (conn->dead) {
118                 conn->free_skipped = true;
119                 return -1;
120         }
121         dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
122         return 0;
123 }
124
125
126 /* initialise a dcerpc connection. 
127    the event context is optional
128 */
129 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
130                                                  struct tevent_context *ev)
131 {
132         struct dcecli_connection *c;
133
134         c = talloc_zero(mem_ctx, struct dcecli_connection);
135         if (!c) {
136                 return NULL;
137         }
138
139         c->event_ctx = ev;
140
141         if (c->event_ctx == NULL) {
142                 talloc_free(c);
143                 return NULL;
144         }
145
146         c->call_id = 1;
147         c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
148         c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
149         c->security_state.auth_context_id = 0;
150         c->security_state.session_key = dcecli_generic_session_key;
151         c->security_state.generic_state = NULL;
152         c->flags = 0;
153         /*
154          * Windows uses 5840 for ncacn_ip_tcp,
155          * so we also use it (for every transport)
156          * by default. But we give the transport
157          * the chance to overwrite it.
158          */
159         c->srv_max_xmit_frag = 5840;
160         c->srv_max_recv_frag = 5840;
161         c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
162         c->pending = NULL;
163
164         c->io_trigger = tevent_create_immediate(c);
165         if (c->io_trigger == NULL) {
166                 talloc_free(c);
167                 return NULL;
168         }
169
170         talloc_set_destructor(c, dcerpc_connection_destructor);
171
172         return c;
173 }
174
175 struct dcerpc_bh_state {
176         struct dcerpc_pipe *p;
177 };
178
179 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
180 {
181         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
182                                      struct dcerpc_bh_state);
183
184         if (!hs->p) {
185                 return false;
186         }
187
188         if (!hs->p->conn) {
189                 return false;
190         }
191
192         if (hs->p->conn->dead) {
193                 return false;
194         }
195
196         return true;
197 }
198
199 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
200                                       uint32_t timeout)
201 {
202         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
203                                      struct dcerpc_bh_state);
204         uint32_t old;
205
206         if (!hs->p) {
207                 return DCERPC_REQUEST_TIMEOUT;
208         }
209
210         old = hs->p->request_timeout;
211         hs->p->request_timeout = timeout;
212
213         return old;
214 }
215
216 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
217                                 enum dcerpc_AuthType *auth_type,
218                                 enum dcerpc_AuthLevel *auth_level)
219 {
220         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
221                                      struct dcerpc_bh_state);
222
223         if (hs->p == NULL) {
224                 return;
225         }
226
227         if (hs->p->conn == NULL) {
228                 return;
229         }
230
231         *auth_type = hs->p->conn->security_state.auth_type;
232         *auth_level = hs->p->conn->security_state.auth_level;
233 }
234
235 struct dcerpc_bh_raw_call_state {
236         struct tevent_context *ev;
237         struct dcerpc_binding_handle *h;
238         DATA_BLOB in_data;
239         DATA_BLOB out_data;
240         uint32_t out_flags;
241         struct rpc_request *subreq;
242 };
243
244 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
245 static bool dcerpc_bh_raw_call_cancel(struct tevent_req *req);
246
247 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
248                                                   struct tevent_context *ev,
249                                                   struct dcerpc_binding_handle *h,
250                                                   const struct GUID *object,
251                                                   uint32_t opnum,
252                                                   uint32_t in_flags,
253                                                   const uint8_t *in_data,
254                                                   size_t in_length)
255 {
256         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
257                                      struct dcerpc_bh_state);
258         struct tevent_req *req;
259         struct dcerpc_bh_raw_call_state *state;
260         bool ok;
261
262         req = tevent_req_create(mem_ctx, &state,
263                                 struct dcerpc_bh_raw_call_state);
264         if (req == NULL) {
265                 return NULL;
266         }
267         state->ev = ev;
268         state->h = h;
269         state->in_data.data = discard_const_p(uint8_t, in_data);
270         state->in_data.length = in_length;
271
272         ok = dcerpc_bh_is_connected(h);
273         if (!ok) {
274                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
275                 return tevent_req_post(req, ev);
276         }
277
278         state->subreq = dcerpc_request_send(state,
279                                             hs->p,
280                                             object,
281                                             opnum,
282                                             &state->in_data);
283         if (tevent_req_nomem(state->subreq, req)) {
284                 return tevent_req_post(req, ev);
285         }
286         state->subreq->async.callback = dcerpc_bh_raw_call_done;
287         state->subreq->async.private_data = req;
288
289         tevent_req_set_cancel_fn(req, dcerpc_bh_raw_call_cancel);
290
291         return req;
292 }
293
294 static bool dcerpc_bh_raw_call_cancel(struct tevent_req *req)
295 {
296         struct dcerpc_bh_raw_call_state *state = tevent_req_data(
297                 req, struct dcerpc_bh_raw_call_state);
298         struct rpc_request *subreq = state->subreq;
299
300         switch (subreq->state) {
301         case RPC_REQUEST_DONE:
302                 /* Can't cancel a complete request */
303                 return false;
304         case RPC_REQUEST_PENDING:
305         {
306                 /* TODO Send CO_CANCEL PDU */
307                 return false;
308         }
309         case RPC_REQUEST_QUEUED:
310         {
311                 /*
312                  * If still queued, just remove from queue and call
313                  * its callback
314                  */
315                 dcerpc_req_dequeue(subreq);
316                 subreq->payload = data_blob_null;
317                 subreq->state = RPC_REQUEST_DONE;
318                 subreq->status = NT_STATUS_RPC_CALL_CANCELLED;
319
320                 /*
321                  * We have to look at shipping further requests before calling
322                  * the async function, that one might close the pipe
323                  */
324                 dcerpc_schedule_io_trigger(subreq->p->conn);
325
326                 if (subreq->async.callback) {
327                         subreq->async.callback(subreq);
328                 }
329                 return true;
330         }
331         }
332
333         return false;
334 }
335
336 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
337 {
338         struct tevent_req *req =
339                 talloc_get_type_abort(subreq->async.private_data,
340                 struct tevent_req);
341         struct dcerpc_bh_raw_call_state *state =
342                 tevent_req_data(req,
343                 struct dcerpc_bh_raw_call_state);
344         NTSTATUS status;
345         uint32_t fault_code;
346
347         state->out_flags = 0;
348         if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
349                 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
350         }
351
352         fault_code = subreq->fault_code;
353
354         status = dcerpc_request_recv(subreq, state, &state->out_data);
355         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
356                 status = dcerpc_fault_to_nt_status(fault_code);
357         }
358
359         /*
360          * We trigger the callback in the next event run
361          * because the code in this file might trigger
362          * multiple request callbacks from within a single
363          * while loop.
364          *
365          * In order to avoid segfaults from within
366          * dcerpc_connection_dead() we call
367          * tevent_req_defer_callback().
368          */
369         tevent_req_defer_callback(req, state->ev);
370
371         if (!NT_STATUS_IS_OK(status)) {
372                 tevent_req_nterror(req, status);
373                 return;
374         }
375
376         tevent_req_done(req);
377 }
378
379 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
380                                         TALLOC_CTX *mem_ctx,
381                                         uint8_t **out_data,
382                                         size_t *out_length,
383                                         uint32_t *out_flags)
384 {
385         struct dcerpc_bh_raw_call_state *state =
386                 tevent_req_data(req,
387                 struct dcerpc_bh_raw_call_state);
388         NTSTATUS status;
389
390         if (tevent_req_is_nterror(req, &status)) {
391                 tevent_req_received(req);
392                 return status;
393         }
394
395         *out_data = talloc_move(mem_ctx, &state->out_data.data);
396         *out_length = state->out_data.length;
397         *out_flags = state->out_flags;
398         tevent_req_received(req);
399         return NT_STATUS_OK;
400 }
401
402 struct dcerpc_bh_disconnect_state {
403         uint8_t _dummy;
404 };
405
406 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
407                                                 struct tevent_context *ev,
408                                                 struct dcerpc_binding_handle *h)
409 {
410         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
411                                      struct dcerpc_bh_state);
412         struct tevent_req *req;
413         struct dcerpc_bh_disconnect_state *state;
414         bool ok;
415
416         req = tevent_req_create(mem_ctx, &state,
417                                 struct dcerpc_bh_disconnect_state);
418         if (req == NULL) {
419                 return NULL;
420         }
421
422         ok = dcerpc_bh_is_connected(h);
423         if (!ok) {
424                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
425                 return tevent_req_post(req, ev);
426         }
427
428         /* TODO: do a real disconnect ... */
429         hs->p = NULL;
430
431         tevent_req_done(req);
432         return tevent_req_post(req, ev);
433 }
434
435 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
436 {
437         NTSTATUS status;
438
439         if (tevent_req_is_nterror(req, &status)) {
440                 tevent_req_received(req);
441                 return status;
442         }
443
444         tevent_req_received(req);
445         return NT_STATUS_OK;
446 }
447
448 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
449 {
450         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
451                                      struct dcerpc_bh_state);
452
453         if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
454                 return true;
455         }
456
457         return false;
458 }
459
460 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
461 {
462         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
463                                      struct dcerpc_bh_state);
464
465         if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
466                 return true;
467         }
468
469         return false;
470 }
471
472 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
473 {
474         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
475                                      struct dcerpc_bh_state);
476
477         if (hs->p->conn->flags & DCERPC_NDR64) {
478                 return true;
479         }
480
481         return false;
482 }
483
484 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
485                                    ndr_flags_type ndr_flags,
486                                    const void *_struct_ptr,
487                                    const struct ndr_interface_call *call)
488 {
489         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
490                                      struct dcerpc_bh_state);
491         void *struct_ptr = discard_const(_struct_ptr);
492         bool print_in = false;
493         bool print_out = false;
494
495         if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
496                 print_in = true;
497         }
498
499         if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
500                 print_out = true;
501         }
502
503         if (DEBUGLEVEL >= 11) {
504                 print_in = true;
505                 print_out = true;
506         }
507
508         if (ndr_flags & NDR_IN) {
509                 if (print_in) {
510                         ndr_print_function_debug(call->ndr_print,
511                                                  call->name,
512                                                  ndr_flags,
513                                                  struct_ptr);
514                 }
515         }
516         if (ndr_flags & NDR_OUT) {
517                 if (print_out) {
518                         ndr_print_function_debug(call->ndr_print,
519                                                  call->name,
520                                                  ndr_flags,
521                                                  struct_ptr);
522                 }
523         }
524 }
525
526 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
527                                       NTSTATUS error,
528                                       const void *struct_ptr,
529                                       const struct ndr_interface_call *call)
530 {
531         DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
532                  call->name, nt_errstr(error)));
533 }
534
535 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
536                                       NTSTATUS error,
537                                       const DATA_BLOB *blob,
538                                       const struct ndr_interface_call *call)
539 {
540         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
541                                      struct dcerpc_bh_state);
542         const uint32_t num_examples = 20;
543         uint32_t i;
544
545         DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
546                  call->name, nt_errstr(error)));
547
548         if (hs->p->conn->packet_log_dir == NULL) return;
549
550         for (i=0;i<num_examples;i++) {
551                 char *name=NULL;
552                 int ret;
553
554                 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
555                                hs->p->conn->packet_log_dir,
556                                call->name, i);
557                 if (ret == -1) {
558                         return;
559                 }
560                 if (!file_exist(name)) {
561                         if (file_save(name, blob->data, blob->length)) {
562                                 DEBUG(10,("Logged rpc packet to %s\n", name));
563                         }
564                         free(name);
565                         break;
566                 }
567                 free(name);
568         }
569 }
570
571 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
572                                           TALLOC_CTX *mem_ctx,
573                                           const DATA_BLOB *blob,
574                                           const struct ndr_interface_call *call)
575 {
576         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
577                                      struct dcerpc_bh_state);
578
579         if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
580                 NTSTATUS status;
581
582                 status = dcerpc_ndr_validate_in(hs->p->conn,
583                                                 mem_ctx,
584                                                 *blob,
585                                                 call->struct_size,
586                                                 call->ndr_push,
587                                                 call->ndr_pull);
588                 if (!NT_STATUS_IS_OK(status)) {
589                         DEBUG(0,("Validation [in] failed for %s - %s\n",
590                                  call->name, nt_errstr(status)));
591                         return status;
592                 }
593         }
594
595         DEBUG(10,("rpc request data:\n"));
596         dump_data(10, blob->data, blob->length);
597
598         return NT_STATUS_OK;
599 }
600
601 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
602                                            struct ndr_pull *pull_in,
603                                            const void *_struct_ptr,
604                                            const struct ndr_interface_call *call)
605 {
606         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
607                                      struct dcerpc_bh_state);
608         void *struct_ptr = discard_const(_struct_ptr);
609
610         DEBUG(10,("rpc reply data:\n"));
611         dump_data(10, pull_in->data, pull_in->data_size);
612
613         if (pull_in->offset != pull_in->data_size) {
614                 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
615                          pull_in->data_size - pull_in->offset,
616                          pull_in->offset, pull_in->offset,
617                          call->name));
618                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
619                    but it turns out that early versions of NT
620                    (specifically NT3.1) add junk onto the end of rpc
621                    packets, so if we want to interoperate at all with
622                    those versions then we need to ignore this error */
623         }
624
625         if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
626                 NTSTATUS status;
627
628                 status = dcerpc_ndr_validate_out(hs->p->conn,
629                                                  pull_in,
630                                                  struct_ptr,
631                                                  call->struct_size,
632                                                  call->ndr_push,
633                                                  call->ndr_pull,
634                                                  call->ndr_print);
635                 if (!NT_STATUS_IS_OK(status)) {
636                         DEBUG(2,("Validation [out] failed for %s - %s\n",
637                                  call->name, nt_errstr(status)));
638                         return status;
639                 }
640         }
641
642         return NT_STATUS_OK;
643 }
644
645 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
646         .name                   = "dcerpc",
647         .is_connected           = dcerpc_bh_is_connected,
648         .set_timeout            = dcerpc_bh_set_timeout,
649         .auth_info              = dcerpc_bh_auth_info,
650         .raw_call_send          = dcerpc_bh_raw_call_send,
651         .raw_call_recv          = dcerpc_bh_raw_call_recv,
652         .disconnect_send        = dcerpc_bh_disconnect_send,
653         .disconnect_recv        = dcerpc_bh_disconnect_recv,
654
655         .push_bigendian         = dcerpc_bh_push_bigendian,
656         .ref_alloc              = dcerpc_bh_ref_alloc,
657         .use_ndr64              = dcerpc_bh_use_ndr64,
658         .do_ndr_print           = dcerpc_bh_do_ndr_print,
659         .ndr_push_failed        = dcerpc_bh_ndr_push_failed,
660         .ndr_pull_failed        = dcerpc_bh_ndr_pull_failed,
661         .ndr_validate_in        = dcerpc_bh_ndr_validate_in,
662         .ndr_validate_out       = dcerpc_bh_ndr_validate_out,
663 };
664
665 /* initialise a dcerpc pipe. */
666 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p,
667                                                          const struct GUID *object,
668                                                          const struct ndr_interface_table *table)
669 {
670         struct dcerpc_binding_handle *h;
671         struct dcerpc_bh_state *hs;
672
673         h = dcerpc_binding_handle_create(p,
674                                          &dcerpc_bh_ops,
675                                          object,
676                                          table,
677                                          &hs,
678                                          struct dcerpc_bh_state,
679                                          __location__);
680         if (h == NULL) {
681                 return NULL;
682         }
683         hs->p = p;
684
685         dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
686
687         return h;
688 }
689
690 /* initialise a dcerpc pipe. */
691 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
692 {
693         struct dcerpc_pipe *p;
694
695         p = talloc_zero(mem_ctx, struct dcerpc_pipe);
696         if (!p) {
697                 return NULL;
698         }
699
700         p->conn = dcerpc_connection_init(p, ev);
701         if (p->conn == NULL) {
702                 talloc_free(p);
703                 return NULL;
704         }
705
706         p->request_timeout = DCERPC_REQUEST_TIMEOUT;
707
708         if (DEBUGLVL(100)) {
709                 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
710         }
711
712         return p;
713 }
714
715
716 /* 
717    choose the next call id to use
718 */
719 static uint32_t next_call_id(struct dcecli_connection *c)
720 {
721         c->call_id++;
722         if (c->call_id == 0) {
723                 c->call_id++;
724         }
725         return c->call_id;
726 }
727
728 /**
729   setup for a ndr pull, also setting up any flags from the binding string
730 */
731 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c, 
732                                             DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
733 {
734         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
735
736         if (ndr == NULL) return ndr;
737
738         if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
739                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
740         }
741
742         if (c->flags & DCERPC_NDR_REF_ALLOC) {
743                 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
744         }
745
746         if (c->flags & DCERPC_NDR64) {
747                 ndr->flags |= LIBNDR_FLAG_NDR64;
748         }
749
750         return ndr;
751 }
752
753 /* 
754    parse the authentication information on a dcerpc response packet
755 */
756 static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
757                                     TALLOC_CTX *mem_ctx,
758                                     enum dcerpc_pkt_type ptype,
759                                     uint8_t required_flags,
760                                     uint8_t optional_flags,
761                                     uint8_t payload_offset,
762                                     DATA_BLOB *payload_and_verifier,
763                                     DATA_BLOB *raw_packet,
764                                     const struct ncacn_packet *pkt)
765 {
766         const struct dcerpc_auth tmp_auth = {
767                 .auth_type = c->security_state.auth_type,
768                 .auth_level = c->security_state.auth_level,
769                 .auth_context_id = c->security_state.auth_context_id,
770         };
771         NTSTATUS status;
772
773         status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
774                                             c->security_state.generic_state,
775                                             true, /* check_pkt_auth_fields */
776                                             mem_ctx,
777                                             ptype,
778                                             required_flags,
779                                             optional_flags,
780                                             payload_offset,
781                                             payload_and_verifier,
782                                             raw_packet,
783                                             pkt);
784         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
785                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
786         }
787         if (!NT_STATUS_IS_OK(status)) {
788                 return status;
789         }
790
791         return NT_STATUS_OK;
792 }
793
794
795 /* 
796    push a dcerpc request packet into a blob, possibly signing it.
797 */
798 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c, 
799                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
800                                          size_t sig_size,
801                                          struct ncacn_packet *pkt)
802 {
803         const struct dcerpc_auth tmp_auth = {
804                 .auth_type = c->security_state.auth_type,
805                 .auth_level = c->security_state.auth_level,
806                 .auth_context_id = c->security_state.auth_context_id,
807         };
808         NTSTATUS status;
809         uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
810
811         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
812                 payload_offset += 16;
813         }
814
815         status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
816                                             c->security_state.generic_state,
817                                             mem_ctx, blob,
818                                             sig_size,
819                                             payload_offset,
820                                             &pkt->u.request.stub_and_verifier,
821                                             pkt);
822         if (!NT_STATUS_IS_OK(status)) {
823                 return status;
824         }
825
826         return NT_STATUS_OK;
827 }
828
829
830 /* 
831    fill in the fixed values in a dcerpc header 
832 */
833 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
834 {
835         pkt->rpc_vers = 5;
836         pkt->rpc_vers_minor = 0;
837         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
838                 pkt->drep[0] = 0;
839         } else {
840                 pkt->drep[0] = DCERPC_DREP_LE;
841         }
842         pkt->drep[1] = 0;
843         pkt->drep[2] = 0;
844         pkt->drep[3] = 0;
845 }
846
847 /*
848   map a bind nak reason to a NTSTATUS
849 */
850 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
851 {
852         switch (reason) {
853         case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
854                 return NT_STATUS_REVISION_MISMATCH;
855         case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
856                 return NT_STATUS_INVALID_PARAMETER;
857         default:
858                 break;
859         }
860         return NT_STATUS_UNSUCCESSFUL;
861 }
862
863 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
864 {
865         if (ack == NULL) {
866                 return NT_STATUS_RPC_PROTOCOL_ERROR;
867         }
868
869         switch (ack->result) {
870         case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
871                 /*
872                  * We have not asked for this...
873                  */
874                 return NT_STATUS_RPC_PROTOCOL_ERROR;
875         default:
876                 break;
877         }
878
879         switch (ack->reason.value) {
880         case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
881                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
882         case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
883                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
884         default:
885                 break;
886         }
887         return NT_STATUS_UNSUCCESSFUL;
888 }
889
890 /*
891   remove requests from the pending or queued queues
892  */
893 static int dcerpc_req_dequeue(struct rpc_request *req)
894 {
895         switch (req->state) {
896         case RPC_REQUEST_QUEUED:
897                 DLIST_REMOVE(req->p->conn->request_queue, req);
898                 break;
899         case RPC_REQUEST_PENDING:
900                 DLIST_REMOVE(req->p->conn->pending, req);
901                 break;
902         case RPC_REQUEST_DONE:
903                 break;
904         }
905         return 0;
906 }
907
908
909 /*
910   mark the dcerpc connection dead. All outstanding requests get an error
911 */
912 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
913 {
914         if (conn->dead) return;
915
916         conn->dead = true;
917
918         TALLOC_FREE(conn->io_trigger);
919         conn->io_trigger_pending = false;
920
921         dcerpc_shutdown_pipe(conn, status);
922
923         /* all pending requests get the error */
924         while (conn->pending) {
925                 struct rpc_request *req = conn->pending;
926                 dcerpc_req_dequeue(req);
927                 req->state = RPC_REQUEST_DONE;
928                 req->status = status;
929                 if (req->async.callback) {
930                         req->async.callback(req);
931                 }
932         }       
933
934         /* all requests, which are not shipped */
935         while (conn->request_queue) {
936                 struct rpc_request *req = conn->request_queue;
937                 dcerpc_req_dequeue(req);
938                 req->state = RPC_REQUEST_DONE;
939                 req->status = status;
940                 if (req->async.callback) {
941                         req->async.callback(req);
942                 }
943         }
944
945         talloc_set_destructor(conn, NULL);
946         if (conn->free_skipped) {
947                 talloc_free(conn);
948         }
949 }
950
951 /*
952   forward declarations of the recv_data handlers for the types of
953   packets we need to handle
954 */
955 static void dcerpc_request_recv_data(struct dcecli_connection *c, 
956                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
957
958 /*
959   receive a dcerpc reply from the transport. Here we work out what
960   type of reply it is (normal request, bind or alter context) and
961   dispatch to the appropriate handler
962 */
963 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
964 {
965         struct ncacn_packet pkt;
966
967         if (conn->dead) {
968                 return;
969         }
970
971         if (NT_STATUS_IS_OK(status) && blob->length == 0) {
972                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
973         }
974
975         /* the transport may be telling us of a severe error, such as
976            a dropped socket */
977         if (!NT_STATUS_IS_OK(status)) {
978                 data_blob_free(blob);
979                 dcerpc_connection_dead(conn, status);
980                 return;
981         }
982
983         /* parse the basic packet to work out what type of response this is */
984         status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
985         if (!NT_STATUS_IS_OK(status)) {
986                 data_blob_free(blob);
987                 dcerpc_connection_dead(conn, status);
988                 return;
989         }
990
991         dcerpc_request_recv_data(conn, blob, &pkt);
992 }
993
994 /*
995   handle timeouts of individual dcerpc requests
996 */
997 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
998                                    struct timeval t, void *private_data)
999 {
1000         struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1001
1002         if (req->ignore_timeout) {
1003                 dcerpc_req_dequeue(req);
1004                 req->state = RPC_REQUEST_DONE;
1005                 req->status = NT_STATUS_IO_TIMEOUT;
1006                 if (req->async.callback) {
1007                         req->async.callback(req);
1008                 }
1009                 return;
1010         }
1011
1012         dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1013 }
1014
1015 struct dcerpc_bind_state {
1016         struct tevent_context *ev;
1017         struct dcerpc_pipe *p;
1018 };
1019
1020 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1021 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1022                                      DATA_BLOB *raw_packet,
1023                                      struct ncacn_packet *pkt);
1024
1025 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1026                                     struct tevent_context *ev,
1027                                     struct dcerpc_pipe *p,
1028                                     const struct ndr_syntax_id *syntax,
1029                                     const struct ndr_syntax_id *transfer_syntax)
1030 {
1031         struct tevent_req *req;
1032         struct dcerpc_bind_state *state;
1033         struct ncacn_packet pkt;
1034         DATA_BLOB blob;
1035         NTSTATUS status;
1036         struct rpc_request *subreq;
1037         uint32_t flags;
1038         struct ndr_syntax_id bind_time_features;
1039
1040         bind_time_features = dcerpc_construct_bind_time_features(
1041                         DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
1042                         DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
1043
1044         req = tevent_req_create(mem_ctx, &state,
1045                                 struct dcerpc_bind_state);
1046         if (req == NULL) {
1047                 return NULL;
1048         }
1049
1050         state->ev = ev;
1051         state->p = p;
1052
1053         p->syntax = *syntax;
1054         p->transfer_syntax = *transfer_syntax;
1055
1056         flags = dcerpc_binding_get_flags(p->binding);
1057
1058         init_ncacn_hdr(p->conn, &pkt);
1059
1060         pkt.ptype = DCERPC_PKT_BIND;
1061         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1062         pkt.call_id = p->conn->call_id;
1063         pkt.auth_length = 0;
1064
1065         if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1066                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1067         }
1068
1069         if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1070                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1071         }
1072
1073         pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1074         pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1075         pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1076         pkt.u.bind.num_contexts = 2;
1077         pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
1078                                                 pkt.u.bind.num_contexts);
1079         if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1080                 return tevent_req_post(req, ev);
1081         }
1082         pkt.u.bind.ctx_list[0].context_id = p->context_id;
1083         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1084         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1085         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1086         pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
1087         pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
1088         pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
1089         pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
1090         pkt.u.bind.auth_info = data_blob(NULL, 0);
1091
1092         /* construct the NDR form of the packet */
1093         status = dcerpc_ncacn_push_auth(&blob,
1094                                 state,
1095                                 &pkt,
1096                                 p->conn->security_state.tmp_auth_info.out);
1097         if (tevent_req_nterror(req, status)) {
1098                 return tevent_req_post(req, ev);
1099         }
1100
1101         /*
1102          * we allocate a dcerpc_request so we can be in the same
1103          * request queue as normal requests
1104          */
1105         subreq = talloc_zero(state, struct rpc_request);
1106         if (tevent_req_nomem(subreq, req)) {
1107                 return tevent_req_post(req, ev);
1108         }
1109
1110         subreq->state = RPC_REQUEST_PENDING;
1111         subreq->call_id = pkt.call_id;
1112         subreq->async.private_data = req;
1113         subreq->async.callback = dcerpc_bind_fail_handler;
1114         subreq->p = p;
1115         subreq->recv_handler = dcerpc_bind_recv_handler;
1116         DLIST_ADD_END(p->conn->pending, subreq);
1117         talloc_set_destructor(subreq, dcerpc_req_dequeue);
1118
1119         status = dcerpc_send_request(p->conn, &blob, true);
1120         if (tevent_req_nterror(req, status)) {
1121                 return tevent_req_post(req, ev);
1122         }
1123
1124         tevent_add_timer(ev, subreq,
1125                          timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1126                          dcerpc_timeout_handler, subreq);
1127
1128         return req;
1129 }
1130
1131 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1132 {
1133         struct tevent_req *req =
1134                 talloc_get_type_abort(subreq->async.private_data,
1135                 struct tevent_req);
1136         struct dcerpc_bind_state *state =
1137                 tevent_req_data(req,
1138                 struct dcerpc_bind_state);
1139         NTSTATUS status = subreq->status;
1140
1141         TALLOC_FREE(subreq);
1142
1143         /*
1144          * We trigger the callback in the next event run
1145          * because the code in this file might trigger
1146          * multiple request callbacks from within a single
1147          * while loop.
1148          *
1149          * In order to avoid segfaults from within
1150          * dcerpc_connection_dead() we call
1151          * tevent_req_defer_callback().
1152          */
1153         tevent_req_defer_callback(req, state->ev);
1154
1155         tevent_req_nterror(req, status);
1156 }
1157
1158 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1159                                      DATA_BLOB *raw_packet,
1160                                      struct ncacn_packet *pkt)
1161 {
1162         struct tevent_req *req =
1163                 talloc_get_type_abort(subreq->async.private_data,
1164                 struct tevent_req);
1165         struct dcerpc_bind_state *state =
1166                 tevent_req_data(req,
1167                 struct dcerpc_bind_state);
1168         struct dcecli_connection *conn = state->p->conn;
1169         struct dcecli_security *sec = &conn->security_state;
1170         struct dcerpc_binding *b = NULL;
1171         NTSTATUS status;
1172         uint32_t flags;
1173
1174         /*
1175          * Note that pkt is allocated under raw_packet->data,
1176          * while raw_packet->data is a child of subreq.
1177          */
1178         talloc_steal(state, raw_packet->data);
1179         TALLOC_FREE(subreq);
1180
1181         /*
1182          * We trigger the callback in the next event run
1183          * because the code in this file might trigger
1184          * multiple request callbacks from within a single
1185          * while loop.
1186          *
1187          * In order to avoid segfaults from within
1188          * dcerpc_connection_dead() we call
1189          * tevent_req_defer_callback().
1190          */
1191         tevent_req_defer_callback(req, state->ev);
1192
1193         if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1194                 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1195
1196                 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1197                          pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1198
1199                 tevent_req_nterror(req, status);
1200                 return;
1201         }
1202
1203         status = dcerpc_verify_ncacn_packet_header(pkt,
1204                                         DCERPC_PKT_BIND_ACK,
1205                                         pkt->u.bind_ack.auth_info.length,
1206                                         DCERPC_PFC_FLAG_FIRST |
1207                                         DCERPC_PFC_FLAG_LAST,
1208                                         DCERPC_PFC_FLAG_CONC_MPX |
1209                                         DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1210         if (!NT_STATUS_IS_OK(status)) {
1211                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1212                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1213                 return;
1214         }
1215
1216         if (pkt->u.bind_ack.num_results < 1) {
1217                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1218                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1219                 return;
1220         }
1221
1222         if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1223                 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1224                 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1225                          pkt->u.bind_ack.ctx_list[0].reason.value,
1226                          nt_errstr(status)));
1227                 tevent_req_nterror(req, status);
1228                 return;
1229         }
1230
1231         if (pkt->u.bind_ack.num_results >= 2) {
1232                 if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1233                         conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
1234                 } else {
1235                         status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
1236                         DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
1237                                  pkt->u.bind_ack.ctx_list[1].reason.value,
1238                                  nt_errstr(status)));
1239                         status = NT_STATUS_OK;
1240                 }
1241         }
1242
1243         /*
1244          * DCE-RPC 1.1 (c706) specifies
1245          * CONST_MUST_RCV_FRAG_SIZE as 1432
1246          */
1247         if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1248                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1249                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1250                 return;
1251         }
1252         if (pkt->u.bind_ack.max_recv_frag < 1432) {
1253                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1254                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1255                 return;
1256         }
1257         conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1258                                       pkt->u.bind_ack.max_xmit_frag);
1259         conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1260                                       pkt->u.bind_ack.max_recv_frag);
1261
1262         flags = dcerpc_binding_get_flags(state->p->binding);
1263
1264         if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1265                 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1266                         conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1267                 } else {
1268                         conn->flags &= ~DCERPC_CONCURRENT_MULTIPLEX;
1269                 }
1270         }
1271
1272         if (!(conn->flags & DCERPC_CONCURRENT_MULTIPLEX)) {
1273                 struct dcerpc_binding *pb =
1274                         discard_const_p(struct dcerpc_binding, state->p->binding);
1275                 /*
1276                  * clear DCERPC_CONCURRENT_MULTIPLEX
1277                  */
1278                 status = dcerpc_binding_set_flags(pb, 0,
1279                                                   DCERPC_CONCURRENT_MULTIPLEX);
1280                 if (tevent_req_nterror(req, status)) {
1281                         return;
1282                 }
1283         }
1284         if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1285             (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1286                 conn->flags |= DCERPC_HEADER_SIGNING;
1287         }
1288
1289         /* the bind_ack might contain a reply set of credentials */
1290         if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1291                 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1292                                                   &pkt->u.bind_ack.auth_info,
1293                                                   sec->tmp_auth_info.in,
1294                                                   NULL, true);
1295                 if (tevent_req_nterror(req, status)) {
1296                         return;
1297                 }
1298         }
1299
1300         /*
1301          * We're the owner of the binding, so we're allowed to modify it.
1302          */
1303         b = discard_const_p(struct dcerpc_binding, state->p->binding);
1304         status = dcerpc_binding_set_assoc_group_id(b,
1305                                                    pkt->u.bind_ack.assoc_group_id);
1306         if (tevent_req_nterror(req, status)) {
1307                 return;
1308         }
1309
1310         tevent_req_done(req);
1311 }
1312
1313 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1314 {
1315         return tevent_req_simple_recv_ntstatus(req);
1316 }
1317
1318 /* 
1319    perform a continued bind (and auth3)
1320 */
1321 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1322                       TALLOC_CTX *mem_ctx)
1323 {
1324         struct ncacn_packet pkt;
1325         NTSTATUS status;
1326         DATA_BLOB blob;
1327         uint32_t flags;
1328
1329         flags = dcerpc_binding_get_flags(p->binding);
1330
1331         init_ncacn_hdr(p->conn, &pkt);
1332
1333         pkt.ptype = DCERPC_PKT_AUTH3;
1334         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1335         pkt.call_id = next_call_id(p->conn);
1336         pkt.auth_length = 0;
1337         pkt.u.auth3.auth_info = data_blob(NULL, 0);
1338
1339         if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1340                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1341         }
1342
1343         /* construct the NDR form of the packet */
1344         status = dcerpc_ncacn_push_auth(&blob,
1345                                 mem_ctx,
1346                                 &pkt,
1347                                 p->conn->security_state.tmp_auth_info.out);
1348         if (!NT_STATUS_IS_OK(status)) {
1349                 return status;
1350         }
1351
1352         /* send it on its way */
1353         status = dcerpc_send_request(p->conn, &blob, false);
1354         if (!NT_STATUS_IS_OK(status)) {
1355                 return status;
1356         }
1357
1358         return NT_STATUS_OK;    
1359 }
1360
1361
1362 /*
1363   process a fragment received from the transport layer during a
1364   request
1365
1366   This function frees the data 
1367 */
1368 static void dcerpc_request_recv_data(struct dcecli_connection *c, 
1369                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1370 {
1371         struct rpc_request *req;
1372         unsigned int length;
1373         NTSTATUS status = NT_STATUS_OK;
1374
1375         /*
1376           if this is an authenticated connection then parse and check
1377           the auth info. We have to do this before finding the
1378           matching packet, as the request structure might have been
1379           removed due to a timeout, but if it has been we still need
1380           to run the auth routines so that we don't get the sign/seal
1381           info out of step with the server
1382         */
1383         switch (pkt->ptype) {
1384         case DCERPC_PKT_RESPONSE:
1385                 status = ncacn_pull_pkt_auth(c, raw_packet->data,
1386                                    DCERPC_PKT_RESPONSE,
1387                                    0, /* required_flags */
1388                                    DCERPC_PFC_FLAG_FIRST |
1389                                    DCERPC_PFC_FLAG_LAST,
1390                                    DCERPC_REQUEST_LENGTH,
1391                                    &pkt->u.response.stub_and_verifier,
1392                                    raw_packet, pkt);
1393                 break;
1394         default:
1395                 break;
1396         }
1397
1398         /* find the matching request */
1399         for (req=c->pending;req;req=req->next) {
1400                 if (pkt->call_id == req->call_id) break;
1401         }
1402
1403 #if 0
1404         /* useful for testing certain vendors RPC servers */
1405         if (req == NULL && c->pending && pkt->call_id == 0) {
1406                 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1407                 req = c->pending;
1408         }
1409 #endif
1410
1411         if (req == NULL) {
1412                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1413                 data_blob_free(raw_packet);
1414                 return;
1415         }
1416
1417         talloc_steal(req, raw_packet->data);
1418
1419         if (req->recv_handler != NULL) {
1420                 dcerpc_req_dequeue(req);
1421                 req->state = RPC_REQUEST_DONE;
1422
1423                 /*
1424                  * We have to look at shipping further requests before calling
1425                  * the async function, that one might close the pipe
1426                  */
1427                 dcerpc_schedule_io_trigger(c);
1428
1429                 req->recv_handler(req, raw_packet, pkt);
1430                 return;
1431         }
1432
1433         if (pkt->ptype == DCERPC_PKT_FAULT) {
1434                 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1435                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1436                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1437                         dcerpc_connection_dead(c, status);
1438                         return;
1439                 }
1440                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1441                         dcerpc_connection_dead(c, status);
1442                         return;
1443                 }
1444                 req->fault_code = pkt->u.fault.status;
1445                 req->status = NT_STATUS_NET_WRITE_FAULT;
1446                 goto req_done;
1447         }
1448
1449         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1450                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1451                          (int)pkt->ptype)); 
1452                 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1453                 return;
1454         }
1455
1456         /* now check the status from the auth routines, and if it failed then fail
1457            this request accordingly */
1458         if (!NT_STATUS_IS_OK(status)) {
1459                 dcerpc_connection_dead(c, status);
1460                 return;
1461         }
1462
1463         length = pkt->u.response.stub_and_verifier.length;
1464
1465         if (req->payload.length + length > c->max_total_response_size) {
1466                 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1467                          (unsigned)req->payload.length + length,
1468                          (unsigned)c->max_total_response_size));
1469                 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1470                 return;
1471         }
1472
1473         if (length > 0) {
1474                 req->payload.data = talloc_realloc(req, 
1475                                                    req->payload.data, 
1476                                                    uint8_t,
1477                                                    req->payload.length + length);
1478                 if (!req->payload.data) {
1479                         req->status = NT_STATUS_NO_MEMORY;
1480                         goto req_done;
1481                 }
1482                 memcpy(req->payload.data+req->payload.length, 
1483                        pkt->u.response.stub_and_verifier.data, length);
1484                 req->payload.length += length;
1485         }
1486
1487         if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1488                 data_blob_free(raw_packet);
1489                 dcerpc_send_read(c);
1490                 return;
1491         }
1492
1493         if (req->verify_bitmask1) {
1494                 req->p->conn->security_state.verified_bitmask1 = true;
1495         }
1496         if (req->verify_pcontext) {
1497                 req->p->verified_pcontext = true;
1498         }
1499
1500         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1501                 req->flags |= DCERPC_PULL_BIGENDIAN;
1502         } else {
1503                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1504         }
1505
1506 req_done:
1507         data_blob_free(raw_packet);
1508
1509         /* we've got the full payload */
1510         dcerpc_req_dequeue(req);
1511         req->state = RPC_REQUEST_DONE;
1512
1513         /*
1514          * We have to look at shipping further requests before calling
1515          * the async function, that one might close the pipe
1516          */
1517         dcerpc_schedule_io_trigger(c);
1518
1519         if (req->async.callback) {
1520                 req->async.callback(req);
1521         }
1522 }
1523
1524 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1525
1526 /*
1527   perform the send side of a async dcerpc request
1528 */
1529 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1530                                                struct dcerpc_pipe *p,
1531                                                const struct GUID *object,
1532                                                uint16_t opnum,
1533                                                DATA_BLOB *stub_data)
1534 {
1535         struct rpc_request *req;
1536         NTSTATUS status;
1537
1538         req = talloc_zero(mem_ctx, struct rpc_request);
1539         if (req == NULL) {
1540                 return NULL;
1541         }
1542
1543         req->p = p;
1544         req->call_id = next_call_id(p->conn);
1545         req->state = RPC_REQUEST_QUEUED;
1546
1547         if (object != NULL) {
1548                 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1549                 if (req->object == NULL) {
1550                         talloc_free(req);
1551                         return NULL;
1552                 }
1553         }
1554
1555         req->opnum = opnum;
1556         req->request_data.length = stub_data->length;
1557         req->request_data.data = stub_data->data;
1558
1559         status = dcerpc_request_prepare_vt(req);
1560         if (!NT_STATUS_IS_OK(status)) {
1561                 talloc_free(req);
1562                 return NULL;
1563         }
1564
1565         DLIST_ADD_END(p->conn->request_queue, req);
1566         talloc_set_destructor(req, dcerpc_req_dequeue);
1567
1568         dcerpc_schedule_io_trigger(p->conn);
1569
1570         if (p->request_timeout) {
1571                 tevent_add_timer(p->conn->event_ctx, req,
1572                                 timeval_current_ofs(p->request_timeout, 0), 
1573                                 dcerpc_timeout_handler, req);
1574         }
1575
1576         return req;
1577 }
1578
1579 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1580 {
1581         struct dcecli_security *sec = &req->p->conn->security_state;
1582         struct dcerpc_sec_verification_trailer *t;
1583         struct dcerpc_sec_vt *c = NULL;
1584         struct ndr_push *ndr = NULL;
1585         enum ndr_err_code ndr_err;
1586
1587         if (sec->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1588                 return NT_STATUS_OK;
1589         }
1590
1591         t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1592         if (t == NULL) {
1593                 return NT_STATUS_NO_MEMORY;
1594         }
1595
1596         if (!sec->verified_bitmask1) {
1597                 t->commands = talloc_realloc(t, t->commands,
1598                                              struct dcerpc_sec_vt,
1599                                              t->count.count + 1);
1600                 if (t->commands == NULL) {
1601                         return NT_STATUS_NO_MEMORY;
1602                 }
1603                 c = &t->commands[t->count.count++];
1604                 ZERO_STRUCTP(c);
1605
1606                 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1607                 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1608                         c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1609                 }
1610                 req->verify_bitmask1 = true;
1611         }
1612
1613         if (!req->p->verified_pcontext) {
1614                 t->commands = talloc_realloc(t, t->commands,
1615                                              struct dcerpc_sec_vt,
1616                                              t->count.count + 1);
1617                 if (t->commands == NULL) {
1618                         return NT_STATUS_NO_MEMORY;
1619                 }
1620                 c = &t->commands[t->count.count++];
1621                 ZERO_STRUCTP(c);
1622
1623                 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1624                 c->u.pcontext.abstract_syntax = req->p->syntax;
1625                 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1626
1627                 req->verify_pcontext = true;
1628         }
1629
1630         if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1631                 t->commands = talloc_realloc(t, t->commands,
1632                                              struct dcerpc_sec_vt,
1633                                              t->count.count + 1);
1634                 if (t->commands == NULL) {
1635                         return NT_STATUS_NO_MEMORY;
1636                 }
1637                 c = &t->commands[t->count.count++];
1638                 ZERO_STRUCTP(c);
1639
1640                 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1641                 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1642                 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1643                         c->u.header2.drep[0] = 0;
1644                 } else {
1645                         c->u.header2.drep[0] = DCERPC_DREP_LE;
1646                 }
1647                 c->u.header2.drep[1] = 0;
1648                 c->u.header2.drep[2] = 0;
1649                 c->u.header2.drep[3] = 0;
1650                 c->u.header2.call_id = req->call_id;
1651                 c->u.header2.context_id = req->p->context_id;
1652                 c->u.header2.opnum = req->opnum;
1653         }
1654
1655         if (t->count.count == 0) {
1656                 TALLOC_FREE(t);
1657                 return NT_STATUS_OK;
1658         }
1659
1660         c = &t->commands[t->count.count - 1];
1661         c->command |= DCERPC_SEC_VT_COMMAND_END;
1662
1663         if (DEBUGLEVEL >= 10) {
1664                 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1665         }
1666
1667         ndr = ndr_push_init_ctx(req);
1668         if (ndr == NULL) {
1669                 return NT_STATUS_NO_MEMORY;
1670         }
1671
1672         /*
1673          * for now we just copy and append
1674          */
1675
1676         ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1677                                  req->request_data.length);
1678         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1679                 return ndr_map_error2ntstatus(ndr_err);
1680         }
1681
1682         ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1683                                                 NDR_SCALARS | NDR_BUFFERS,
1684                                                 t);
1685         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1686                 return ndr_map_error2ntstatus(ndr_err);
1687         }
1688         req->request_data = ndr_push_blob(ndr);
1689
1690         return NT_STATUS_OK;
1691 }
1692
1693 /*
1694   Send a request using the transport
1695 */
1696
1697 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1698 {
1699         struct rpc_request *req;
1700         struct dcerpc_pipe *p;
1701         DATA_BLOB *stub_data;
1702         struct ncacn_packet pkt;
1703         DATA_BLOB blob;
1704         uint32_t remaining, chunk_size;
1705         bool first_packet = true;
1706         size_t sig_size = 0;
1707         bool need_async = false;
1708         bool can_async = true;
1709
1710         req = c->request_queue;
1711         if (req == NULL) {
1712                 return;
1713         }
1714
1715         p = req->p;
1716         stub_data = &req->request_data;
1717
1718         if (c->pending) {
1719                 need_async = true;
1720         }
1721
1722         if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1723                 can_async = gensec_have_feature(c->security_state.generic_state,
1724                                                 GENSEC_FEATURE_ASYNC_REPLIES);
1725         }
1726
1727         if (need_async && !can_async) {
1728                 req->wait_for_sync = true;
1729                 return;
1730         }
1731
1732         DLIST_REMOVE(c->request_queue, req);
1733         DLIST_ADD(c->pending, req);
1734         req->state = RPC_REQUEST_PENDING;
1735
1736         init_ncacn_hdr(p->conn, &pkt);
1737
1738         remaining = stub_data->length;
1739
1740         /* we can write a full max_recv_frag size, minus the dcerpc
1741            request header size */
1742         chunk_size = p->conn->srv_max_recv_frag;
1743         chunk_size -= DCERPC_REQUEST_LENGTH;
1744         if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1745                 size_t max_payload = chunk_size;
1746
1747                 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1748                 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1749
1750                 sig_size = gensec_sig_size(c->security_state.generic_state,
1751                                            max_payload);
1752                 if (sig_size) {
1753                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1754                         chunk_size -= sig_size;
1755                 }
1756         }
1757         chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1758
1759         pkt.ptype = DCERPC_PKT_REQUEST;
1760         pkt.call_id = req->call_id;
1761         pkt.auth_length = 0;
1762         pkt.pfc_flags = 0;
1763         pkt.u.request.context_id = p->context_id;
1764         pkt.u.request.opnum = req->opnum;
1765
1766         if (req->object) {
1767                 pkt.u.request.object.object = *req->object;
1768                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1769                 chunk_size -= ndr_size_GUID(req->object,0);
1770         }
1771
1772         /* we send a series of pdus without waiting for a reply */
1773         while (remaining > 0 || first_packet) {
1774                 uint32_t chunk = MIN(chunk_size, remaining);
1775                 bool last_frag = false;
1776                 bool do_trans = false;
1777
1778                 first_packet = false;
1779                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1780
1781                 if (remaining == stub_data->length) {
1782                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1783                 }
1784                 if (chunk == remaining) {
1785                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1786                         last_frag = true;
1787                 }
1788
1789                 pkt.u.request.alloc_hint = remaining;
1790                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1791                         (stub_data->length - remaining);
1792                 pkt.u.request.stub_and_verifier.length = chunk;
1793
1794                 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1795                 if (!NT_STATUS_IS_OK(req->status)) {
1796                         req->state = RPC_REQUEST_DONE;
1797                         DLIST_REMOVE(p->conn->pending, req);
1798                         return;
1799                 }
1800
1801                 if (last_frag && !need_async) {
1802                         do_trans = true;
1803                 }
1804
1805                 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1806                 if (!NT_STATUS_IS_OK(req->status)) {
1807                         req->state = RPC_REQUEST_DONE;
1808                         DLIST_REMOVE(p->conn->pending, req);
1809                         return;
1810                 }               
1811
1812                 if (last_frag && !do_trans) {
1813                         req->status = dcerpc_send_read(p->conn);
1814                         if (!NT_STATUS_IS_OK(req->status)) {
1815                                 req->state = RPC_REQUEST_DONE;
1816                                 DLIST_REMOVE(p->conn->pending, req);
1817                                 return;
1818                         }
1819                 }
1820
1821                 remaining -= chunk;
1822         }
1823 }
1824
1825 static void dcerpc_io_trigger(struct tevent_context *ctx,
1826                               struct tevent_immediate *im,
1827                               void *private_data)
1828 {
1829         struct dcecli_connection *c =
1830                 talloc_get_type_abort(private_data,
1831                 struct dcecli_connection);
1832
1833         c->io_trigger_pending = false;
1834
1835         dcerpc_schedule_io_trigger(c);
1836
1837         dcerpc_ship_next_request(c);
1838 }
1839
1840 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1841 {
1842         if (c->dead) {
1843                 return;
1844         }
1845
1846         if (c->request_queue == NULL) {
1847                 return;
1848         }
1849
1850         if (c->request_queue->wait_for_sync && c->pending) {
1851                 return;
1852         }
1853
1854         if (c->io_trigger_pending) {
1855                 return;
1856         }
1857
1858         c->io_trigger_pending = true;
1859
1860         tevent_schedule_immediate(c->io_trigger,
1861                                   c->event_ctx,
1862                                   dcerpc_io_trigger,
1863                                   c);
1864 }
1865
1866 /*
1867   perform the receive side of a async dcerpc request
1868 */
1869 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1870                                     TALLOC_CTX *mem_ctx,
1871                                     DATA_BLOB *stub_data)
1872 {
1873         NTSTATUS status;
1874
1875         while (req->state != RPC_REQUEST_DONE) {
1876                 struct tevent_context *ctx = req->p->conn->event_ctx;
1877                 if (tevent_loop_once(ctx) != 0) {
1878                         return NT_STATUS_CONNECTION_DISCONNECTED;
1879                 }
1880         }
1881         *stub_data = req->payload;
1882         status = req->status;
1883         if (stub_data->data) {
1884                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1885         }
1886         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1887                 req->p->last_fault_code = req->fault_code;
1888         }
1889         talloc_unlink(talloc_parent(req), req);
1890         return status;
1891 }
1892
1893 /*
1894   this is a paranoid NDR validator. For every packet we push onto the wire
1895   we pull it back again, then push it again. Then we compare the raw NDR data
1896   for that to the NDR we initially generated. If they don't match then we know
1897   we must have a bug in either the pull or push side of our code
1898 */
1899 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c, 
1900                                        TALLOC_CTX *mem_ctx,
1901                                        DATA_BLOB blob,
1902                                        size_t struct_size,
1903                                        ndr_push_flags_fn_t ndr_push,
1904                                        ndr_pull_flags_fn_t ndr_pull)
1905 {
1906         void *st;
1907         struct ndr_pull *pull;
1908         struct ndr_push *push;
1909         DATA_BLOB blob2;
1910         enum ndr_err_code ndr_err;
1911
1912         st = talloc_size(mem_ctx, struct_size);
1913         if (!st) {
1914                 return NT_STATUS_NO_MEMORY;
1915         }
1916
1917         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1918         if (!pull) {
1919                 return NT_STATUS_NO_MEMORY;
1920         }
1921         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1922
1923         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1924                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1925         }
1926
1927         if (c->flags & DCERPC_NDR64) {
1928                 pull->flags |= LIBNDR_FLAG_NDR64;
1929         }
1930
1931         ndr_err = ndr_pull(pull, NDR_IN, st);
1932         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1933                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1934                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1935                                          "failed input validation pull - %s",
1936                                          nt_errstr(status));
1937                 return ndr_map_error2ntstatus(ndr_err);
1938         }
1939
1940         push = ndr_push_init_ctx(mem_ctx);
1941         if (!push) {
1942                 return NT_STATUS_NO_MEMORY;
1943         }       
1944
1945         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1946                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1947         }
1948
1949         if (c->flags & DCERPC_NDR64) {
1950                 push->flags |= LIBNDR_FLAG_NDR64;
1951         }
1952
1953         ndr_err = ndr_push(push, NDR_IN, st);
1954         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1955                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1956                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1957                                          "failed input validation push - %s",
1958                                          nt_errstr(status));
1959                 return ndr_map_error2ntstatus(ndr_err);
1960         }
1961
1962         blob2 = ndr_push_blob(push);
1963
1964         if (data_blob_cmp(&blob, &blob2) != 0) {
1965                 DEBUG(3,("original:\n"));
1966                 dump_data(3, blob.data, blob.length);
1967                 DEBUG(3,("secondary:\n"));
1968                 dump_data(3, blob2.data, blob2.length);
1969                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1970                                          "failed input validation blobs doesn't match");
1971                 return ndr_map_error2ntstatus(ndr_err);
1972         }
1973
1974         return NT_STATUS_OK;
1975 }
1976
1977 /*
1978   this is a paranoid NDR input validator. For every packet we pull
1979   from the wire we push it back again then pull and push it
1980   again. Then we compare the raw NDR data for that to the NDR we
1981   initially generated. If they don't match then we know we must have a
1982   bug in either the pull or push side of our code
1983 */
1984 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1985                                         struct ndr_pull *pull_in,
1986                                         void *struct_ptr,
1987                                         size_t struct_size,
1988                                         ndr_push_flags_fn_t ndr_push,
1989                                         ndr_pull_flags_fn_t ndr_pull,
1990                                         ndr_print_function_t ndr_print)
1991 {
1992         void *st;
1993         struct ndr_pull *pull;
1994         struct ndr_push *push;
1995         DATA_BLOB blob, blob2;
1996         TALLOC_CTX *mem_ctx = pull_in;
1997         char *s1, *s2;
1998         enum ndr_err_code ndr_err;
1999
2000         st = talloc_size(mem_ctx, struct_size);
2001         if (!st) {
2002                 return NT_STATUS_NO_MEMORY;
2003         }
2004         memcpy(st, struct_ptr, struct_size);
2005
2006         push = ndr_push_init_ctx(mem_ctx);
2007         if (!push) {
2008                 return NT_STATUS_NO_MEMORY;
2009         }       
2010
2011         ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2012         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2013                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2014                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2015                                          "failed output validation push - %s",
2016                                          nt_errstr(status));
2017                 return ndr_map_error2ntstatus(ndr_err);
2018         }
2019
2020         blob = ndr_push_blob(push);
2021
2022         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2023         if (!pull) {
2024                 return NT_STATUS_NO_MEMORY;
2025         }
2026
2027         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2028         ndr_err = ndr_pull(pull, NDR_OUT, st);
2029         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2030                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2031                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2032                                          "failed output validation pull - %s",
2033                                          nt_errstr(status));
2034                 return ndr_map_error2ntstatus(ndr_err);
2035         }
2036
2037         push = ndr_push_init_ctx(mem_ctx);
2038         if (!push) {
2039                 return NT_STATUS_NO_MEMORY;
2040         }       
2041
2042         ndr_err = ndr_push(push, NDR_OUT, st);
2043         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2044                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2045                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2046                                          "failed output validation push2 - %s",
2047                                          nt_errstr(status));
2048                 return ndr_map_error2ntstatus(ndr_err);
2049         }
2050
2051         blob2 = ndr_push_blob(push);
2052
2053         if (data_blob_cmp(&blob, &blob2) != 0) {
2054                 DEBUG(3,("original:\n"));
2055                 dump_data(3, blob.data, blob.length);
2056                 DEBUG(3,("secondary:\n"));
2057                 dump_data(3, blob2.data, blob2.length);
2058                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2059                                          "failed output validation blobs doesn't match");
2060                 return ndr_map_error2ntstatus(ndr_err);
2061         }
2062
2063         /* this checks the printed forms of the two structures, which effectively
2064            tests all of the value() attributes */
2065         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
2066                                        NDR_OUT, struct_ptr);
2067         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
2068                                        NDR_OUT, st);
2069         if (strcmp(s1, s2) != 0) {
2070 #if 1
2071                 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2072 #else
2073                 /* this is sometimes useful */
2074                 printf("VALIDATE ERROR\n");
2075                 file_save("wire.dat", s1, strlen(s1));
2076                 file_save("gen.dat", s2, strlen(s2));
2077                 system("diff -u wire.dat gen.dat");
2078 #endif
2079                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2080                                          "failed output validation strings doesn't match");
2081                 return ndr_map_error2ntstatus(ndr_err);
2082         }
2083
2084         return NT_STATUS_OK;
2085 }
2086
2087 /*
2088   a useful function for retrieving the server name we connected to
2089 */
2090 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2091 {
2092         return p->conn ? p->conn->server_name : NULL;
2093 }
2094
2095
2096 /*
2097   get the dcerpc auth_level for a open connection
2098 */
2099 uint32_t dcerpc_auth_level(struct dcecli_connection *c) 
2100 {
2101         uint8_t auth_level;
2102
2103         if (c->flags & DCERPC_SEAL) {
2104                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2105         } else if (c->flags & DCERPC_SIGN) {
2106                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2107         } else if (c->flags & DCERPC_PACKET) {
2108                 auth_level = DCERPC_AUTH_LEVEL_PACKET;
2109         } else if (c->flags & DCERPC_CONNECT) {
2110                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2111         } else {
2112                 auth_level = DCERPC_AUTH_LEVEL_NONE;
2113         }
2114         return auth_level;
2115 }
2116
2117 struct dcerpc_alter_context_state {
2118         struct tevent_context *ev;
2119         struct dcerpc_pipe *p;
2120 };
2121
2122 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2123 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2124                                               DATA_BLOB *raw_packet,
2125                                               struct ncacn_packet *pkt);
2126
2127 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2128                                              struct tevent_context *ev,
2129                                              struct dcerpc_pipe *p,
2130                                              const struct ndr_syntax_id *syntax,
2131                                              const struct ndr_syntax_id *transfer_syntax)
2132 {
2133         struct tevent_req *req;
2134         struct dcerpc_alter_context_state *state;
2135         struct ncacn_packet pkt;
2136         DATA_BLOB blob;
2137         NTSTATUS status;
2138         struct rpc_request *subreq;
2139         uint32_t flags;
2140
2141         req = tevent_req_create(mem_ctx, &state,
2142                                 struct dcerpc_alter_context_state);
2143         if (req == NULL) {
2144                 return NULL;
2145         }
2146
2147         state->ev = ev;
2148         state->p = p;
2149
2150         p->syntax = *syntax;
2151         p->transfer_syntax = *transfer_syntax;
2152
2153         flags = dcerpc_binding_get_flags(p->binding);
2154
2155         init_ncacn_hdr(p->conn, &pkt);
2156
2157         pkt.ptype = DCERPC_PKT_ALTER;
2158         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2159         pkt.call_id = p->conn->call_id;
2160         pkt.auth_length = 0;
2161
2162         if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2163                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2164         }
2165
2166         pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2167         pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2168         pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2169         pkt.u.alter.num_contexts = 1;
2170         pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
2171                                                  pkt.u.alter.num_contexts);
2172         if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2173                 return tevent_req_post(req, ev);
2174         }
2175         pkt.u.alter.ctx_list[0].context_id = p->context_id;
2176         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2177         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2178         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2179         pkt.u.alter.auth_info = data_blob(NULL, 0);
2180
2181         /* construct the NDR form of the packet */
2182         status = dcerpc_ncacn_push_auth(&blob,
2183                                 state,
2184                                 &pkt,
2185                                 p->conn->security_state.tmp_auth_info.out);
2186         if (tevent_req_nterror(req, status)) {
2187                 return tevent_req_post(req, ev);
2188         }
2189
2190         /*
2191          * we allocate a dcerpc_request so we can be in the same
2192          * request queue as normal requests
2193          */
2194         subreq = talloc_zero(state, struct rpc_request);
2195         if (tevent_req_nomem(subreq, req)) {
2196                 return tevent_req_post(req, ev);
2197         }
2198
2199         subreq->state = RPC_REQUEST_PENDING;
2200         subreq->call_id = pkt.call_id;
2201         subreq->async.private_data = req;
2202         subreq->async.callback = dcerpc_alter_context_fail_handler;
2203         subreq->p = p;
2204         subreq->recv_handler = dcerpc_alter_context_recv_handler;
2205         DLIST_ADD_END(p->conn->pending, subreq);
2206         talloc_set_destructor(subreq, dcerpc_req_dequeue);
2207
2208         status = dcerpc_send_request(p->conn, &blob, true);
2209         if (tevent_req_nterror(req, status)) {
2210                 return tevent_req_post(req, ev);
2211         }
2212
2213         tevent_add_timer(ev, subreq,
2214                          timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2215                          dcerpc_timeout_handler, subreq);
2216
2217         return req;
2218 }
2219
2220 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2221 {
2222         struct tevent_req *req =
2223                 talloc_get_type_abort(subreq->async.private_data,
2224                 struct tevent_req);
2225         struct dcerpc_alter_context_state *state =
2226                 tevent_req_data(req,
2227                 struct dcerpc_alter_context_state);
2228         NTSTATUS status = subreq->status;
2229
2230         TALLOC_FREE(subreq);
2231
2232         /*
2233          * We trigger the callback in the next event run
2234          * because the code in this file might trigger
2235          * multiple request callbacks from within a single
2236          * while loop.
2237          *
2238          * In order to avoid segfaults from within
2239          * dcerpc_connection_dead() we call
2240          * tevent_req_defer_callback().
2241          */
2242         tevent_req_defer_callback(req, state->ev);
2243
2244         tevent_req_nterror(req, status);
2245 }
2246
2247 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2248                                               DATA_BLOB *raw_packet,
2249                                               struct ncacn_packet *pkt)
2250 {
2251         struct tevent_req *req =
2252                 talloc_get_type_abort(subreq->async.private_data,
2253                 struct tevent_req);
2254         struct dcerpc_alter_context_state *state =
2255                 tevent_req_data(req,
2256                 struct dcerpc_alter_context_state);
2257         struct dcecli_connection *conn = state->p->conn;
2258         struct dcecli_security *sec = &conn->security_state;
2259         NTSTATUS status;
2260
2261         /*
2262          * Note that pkt is allocated under raw_packet->data,
2263          * while raw_packet->data is a child of subreq.
2264          */
2265         talloc_steal(state, raw_packet->data);
2266         TALLOC_FREE(subreq);
2267
2268         /*
2269          * We trigger the callback in the next event run
2270          * because the code in this file might trigger
2271          * multiple request callbacks from within a single
2272          * while loop.
2273          *
2274          * In order to avoid segfaults from within
2275          * dcerpc_connection_dead() we call
2276          * tevent_req_defer_callback().
2277          */
2278         tevent_req_defer_callback(req, state->ev);
2279
2280         if (pkt->ptype == DCERPC_PKT_FAULT) {
2281                 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2282                          dcerpc_errstr(state, pkt->u.fault.status)));
2283                 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2284                         state->p->last_fault_code = pkt->u.fault.status;
2285                         tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2286                 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2287                         state->p->last_fault_code = pkt->u.fault.status;
2288                         tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2289                 } else {
2290                         state->p->last_fault_code = pkt->u.fault.status;
2291                         status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2292                         tevent_req_nterror(req, status);
2293                 }
2294                 return;
2295         }
2296
2297         status = dcerpc_verify_ncacn_packet_header(pkt,
2298                                         DCERPC_PKT_ALTER_RESP,
2299                                         pkt->u.alter_resp.auth_info.length,
2300                                         DCERPC_PFC_FLAG_FIRST |
2301                                         DCERPC_PFC_FLAG_LAST,
2302                                         DCERPC_PFC_FLAG_CONC_MPX |
2303                                         DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2304         if (!NT_STATUS_IS_OK(status)) {
2305                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2306                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2307                 return;
2308         }
2309
2310         if (pkt->u.alter_resp.num_results != 1) {
2311                 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2312                 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2313                 return;
2314         }
2315
2316         if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2317                 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2318                 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2319                          pkt->u.alter_resp.ctx_list[0].reason.value,
2320                          nt_errstr(status)));
2321                 tevent_req_nterror(req, status);
2322                 return;
2323         }
2324
2325         /* the alter_resp might contain a reply set of credentials */
2326         if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2327                 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2328                                                   &pkt->u.alter_resp.auth_info,
2329                                                   sec->tmp_auth_info.in,
2330                                                   NULL, true);
2331                 if (tevent_req_nterror(req, status)) {
2332                         return;
2333                 }
2334         }
2335
2336         tevent_req_done(req);
2337 }
2338
2339 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2340 {
2341         return tevent_req_simple_recv_ntstatus(req);
2342 }
2343
2344 /* 
2345    send a dcerpc alter_context request
2346 */
2347 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
2348                               TALLOC_CTX *mem_ctx,
2349                               const struct ndr_syntax_id *syntax,
2350                               const struct ndr_syntax_id *transfer_syntax)
2351 {
2352         struct tevent_req *subreq;
2353         struct tevent_context *ev = p->conn->event_ctx;
2354         bool ok;
2355
2356         /* TODO: create a new event context here */
2357
2358         subreq = dcerpc_alter_context_send(mem_ctx, ev,
2359                                            p, syntax, transfer_syntax);
2360         if (subreq == NULL) {
2361                 return NT_STATUS_NO_MEMORY;
2362         }
2363
2364         ok = tevent_req_poll(subreq, ev);
2365         if (!ok) {
2366                 NTSTATUS status;
2367                 status = map_nt_error_from_unix_common(errno);
2368                 return status;
2369         }
2370
2371         return dcerpc_alter_context_recv(subreq);
2372 }
2373
2374 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2375 {
2376         if (c->transport.stream == NULL) {
2377                 return;
2378         }
2379
2380         tevent_queue_stop(c->transport.write_queue);
2381         TALLOC_FREE(c->transport.read_subreq);
2382         TALLOC_FREE(c->transport.stream);
2383
2384         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2385                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2386         }
2387
2388         if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2389                 status = NT_STATUS_END_OF_FILE;
2390         }
2391
2392         dcerpc_recv_data(c, NULL, status);
2393 }
2394
2395
2396 /*
2397    shutdown SMB pipe connection
2398 */
2399 struct dcerpc_shutdown_pipe_state {
2400         struct dcecli_connection *c;
2401         NTSTATUS status;
2402 };
2403
2404 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2405
2406 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2407 {
2408         struct dcerpc_shutdown_pipe_state *state;
2409         struct tevent_req *subreq;
2410
2411         if (c->transport.stream == NULL) {
2412                 return NT_STATUS_OK;
2413         }
2414
2415         state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2416         if (state == NULL) {
2417                 return NT_STATUS_NO_MEMORY;
2418         }
2419         state->c = c;
2420         state->status = status;
2421
2422         subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2423         if (subreq == NULL) {
2424                 return NT_STATUS_NO_MEMORY;
2425         }
2426         tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2427
2428         return status;
2429 }
2430
2431 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2432 {
2433         struct dcerpc_shutdown_pipe_state *state =
2434                 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2435         struct dcecli_connection *c = state->c;
2436         NTSTATUS status = state->status;
2437         int error;
2438
2439         /*
2440          * here we ignore the return values...
2441          */
2442         tstream_disconnect_recv(subreq, &error);
2443         TALLOC_FREE(subreq);
2444
2445         TALLOC_FREE(state);
2446
2447         dcerpc_transport_dead(c, status);
2448 }
2449
2450
2451
2452 struct dcerpc_send_read_state {
2453         struct dcecli_connection *p;
2454 };
2455
2456 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2457 {
2458         struct dcecli_connection *p = state->p;
2459
2460         p->transport.read_subreq = NULL;
2461
2462         return 0;
2463 }
2464
2465 static void dcerpc_send_read_done(struct tevent_req *subreq);
2466
2467 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2468 {
2469         struct dcerpc_send_read_state *state;
2470
2471         if (p->transport.read_subreq != NULL) {
2472                 p->transport.pending_reads++;
2473                 return NT_STATUS_OK;
2474         }
2475
2476         state = talloc_zero(p, struct dcerpc_send_read_state);
2477         if (state == NULL) {
2478                 return NT_STATUS_NO_MEMORY;
2479         }
2480         state->p = p;
2481
2482         talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2483
2484         p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2485                                                           p->event_ctx,
2486                                                           p->transport.stream);
2487         if (p->transport.read_subreq == NULL) {
2488                 return NT_STATUS_NO_MEMORY;
2489         }
2490         tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2491
2492         return NT_STATUS_OK;
2493 }
2494
2495 static void dcerpc_send_read_done(struct tevent_req *subreq)
2496 {
2497         struct dcerpc_send_read_state *state =
2498                 tevent_req_callback_data(subreq,
2499                                          struct dcerpc_send_read_state);
2500         struct dcecli_connection *p = state->p;
2501         NTSTATUS status;
2502         struct ncacn_packet *pkt;
2503         DATA_BLOB blob;
2504
2505         status = dcerpc_read_ncacn_packet_recv(subreq, state,
2506                                                &pkt, &blob);
2507         TALLOC_FREE(subreq);
2508         if (!NT_STATUS_IS_OK(status)) {
2509                 TALLOC_FREE(state);
2510                 dcerpc_transport_dead(p, status);
2511                 return;
2512         }
2513
2514         /*
2515          * here we steal into thet connection context,
2516          * but p->transport.recv_data() will steal or free it again
2517          */
2518         talloc_steal(p, blob.data);
2519         TALLOC_FREE(state);
2520
2521         if (p->transport.pending_reads > 0) {
2522                 p->transport.pending_reads--;
2523
2524                 status = dcerpc_send_read(p);
2525                 if (!NT_STATUS_IS_OK(status)) {
2526                         dcerpc_transport_dead(p, status);
2527                         return;
2528                 }
2529         }
2530
2531         dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2532 }
2533
2534 struct dcerpc_send_request_state {
2535         struct dcecli_connection *p;
2536         DATA_BLOB blob;
2537         struct iovec iov;
2538 };
2539
2540 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2541 {
2542         struct dcecli_connection *p = state->p;
2543
2544         p->transport.read_subreq = NULL;
2545
2546         return 0;
2547 }
2548
2549 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2550 static void dcerpc_send_request_done(struct tevent_req *subreq);
2551
2552 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2553                                     bool trigger_read)
2554 {
2555         struct dcerpc_send_request_state *state;
2556         struct tevent_req *subreq;
2557         bool use_trans = trigger_read;
2558
2559         if (p->transport.stream == NULL) {
2560                 return NT_STATUS_CONNECTION_DISCONNECTED;
2561         }
2562
2563         state = talloc_zero(p, struct dcerpc_send_request_state);
2564         if (state == NULL) {
2565                 return NT_STATUS_NO_MEMORY;
2566         }
2567         state->p = p;
2568
2569         state->blob = data_blob_talloc(state, data->data, data->length);
2570         if (state->blob.data == NULL) {
2571                 TALLOC_FREE(state);
2572                 return NT_STATUS_NO_MEMORY;
2573         }
2574         state->iov.iov_base = (void *)state->blob.data;
2575         state->iov.iov_len = state->blob.length;
2576
2577         if (p->transport.read_subreq != NULL) {
2578                 use_trans = false;
2579         }
2580
2581         if (!tstream_is_smbXcli_np(p->transport.stream)) {
2582                 use_trans = false;
2583         }
2584
2585         if (use_trans) {
2586                 /*
2587                  * we need to block reads until our write is
2588                  * the next in the write queue.
2589                  */
2590                 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2591                                                              p->transport.write_queue);
2592                 if (p->transport.read_subreq == NULL) {
2593                         TALLOC_FREE(state);
2594                         return NT_STATUS_NO_MEMORY;
2595                 }
2596                 tevent_req_set_callback(p->transport.read_subreq,
2597                                         dcerpc_send_request_wait_done,
2598                                         state);
2599
2600                 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2601
2602                 trigger_read = false;
2603         }
2604
2605         subreq = tstream_writev_queue_send(state, p->event_ctx,
2606                                            p->transport.stream,
2607                                            p->transport.write_queue,
2608                                            &state->iov, 1);
2609         if (subreq == NULL) {
2610                 TALLOC_FREE(state);
2611                 return NT_STATUS_NO_MEMORY;
2612         }
2613         tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2614
2615         if (trigger_read) {
2616                 dcerpc_send_read(p);
2617         }
2618
2619         return NT_STATUS_OK;
2620 }
2621
2622 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2623 {
2624         struct dcerpc_send_request_state *state =
2625                 tevent_req_callback_data(subreq,
2626                 struct dcerpc_send_request_state);
2627         struct dcecli_connection *p = state->p;
2628         NTSTATUS status;
2629         bool ok;
2630
2631         p->transport.read_subreq = NULL;
2632         talloc_set_destructor(state, NULL);
2633
2634         ok = tevent_queue_wait_recv(subreq);
2635         if (!ok) {
2636                 TALLOC_FREE(state);
2637                 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2638                 return;
2639         }
2640
2641         if (tevent_queue_length(p->transport.write_queue) <= 2) {
2642                 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2643                 if (!NT_STATUS_IS_OK(status)) {
2644                         TALLOC_FREE(state);
2645                         dcerpc_transport_dead(p, status);
2646                         return;
2647                 }
2648         }
2649
2650         /* we free subreq after tstream_cli_np_use_trans */
2651         TALLOC_FREE(subreq);
2652
2653         dcerpc_send_read(p);
2654 }
2655
2656 static void dcerpc_send_request_done(struct tevent_req *subreq)
2657 {
2658         struct dcerpc_send_request_state *state =
2659                 tevent_req_callback_data(subreq,
2660                 struct dcerpc_send_request_state);
2661         int ret;
2662         int error;
2663
2664         ret = tstream_writev_queue_recv(subreq, &error);
2665         TALLOC_FREE(subreq);
2666         if (ret == -1) {
2667                 struct dcecli_connection *p = state->p;
2668                 NTSTATUS status = map_nt_error_from_unix_common(error);
2669
2670                 TALLOC_FREE(state);
2671                 dcerpc_transport_dead(p, status);
2672                 return;
2673         }
2674
2675         TALLOC_FREE(state);
2676 }