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