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