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