32436447218b519d643463fd461ba3516fe2af91
[sfrench/samba-autobuild/.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 "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.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
36 enum rpc_request_state {
37         RPC_REQUEST_QUEUED,
38         RPC_REQUEST_PENDING,
39         RPC_REQUEST_DONE
40 };
41
42 /*
43   handle for an async dcerpc request
44 */
45 struct rpc_request {
46         struct rpc_request *next, *prev;
47         struct dcerpc_pipe *p;
48         NTSTATUS status;
49         uint32_t call_id;
50         enum rpc_request_state state;
51         DATA_BLOB payload;
52         uint32_t flags;
53         uint32_t fault_code;
54
55         /* this is used to distinguish bind and alter_context requests
56            from normal requests */
57         void (*recv_handler)(struct rpc_request *conn, 
58                              DATA_BLOB *blob, struct ncacn_packet *pkt);
59
60         const struct GUID *object;
61         uint16_t opnum;
62         DATA_BLOB request_data;
63         bool ignore_timeout;
64
65         /* use by the ndr level async recv call */
66         struct {
67                 const struct ndr_interface_table *table;
68                 uint32_t opnum;
69                 void *struct_ptr;
70                 TALLOC_CTX *mem_ctx;
71         } ndr;
72
73         struct {
74                 void (*callback)(struct rpc_request *);
75                 void *private_data;
76         } async;
77 };
78
79 _PUBLIC_ NTSTATUS dcerpc_init(void)
80 {
81         return gensec_init();
82 }
83
84 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
85 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
86
87 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
88                                                const struct GUID *object,
89                                                uint16_t opnum,
90                                                DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
92                                     TALLOC_CTX *mem_ctx,
93                                     DATA_BLOB *stub_data);
94 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
95                                        TALLOC_CTX *mem_ctx,
96                                        DATA_BLOB blob,
97                                        size_t struct_size,
98                                        ndr_push_flags_fn_t ndr_push,
99                                        ndr_pull_flags_fn_t ndr_pull);
100 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
101                                         struct ndr_pull *pull_in,
102                                         void *struct_ptr,
103                                         size_t struct_size,
104                                         ndr_push_flags_fn_t ndr_push,
105                                         ndr_pull_flags_fn_t ndr_pull,
106                                         ndr_print_function_t ndr_print);
107
108 /* destroy a dcerpc connection */
109 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
110 {
111         if (conn->dead) {
112                 conn->free_skipped = true;
113                 return -1;
114         }
115         dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
116         return 0;
117 }
118
119
120 /* initialise a dcerpc connection. 
121    the event context is optional
122 */
123 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
124                                                  struct tevent_context *ev)
125 {
126         struct dcecli_connection *c;
127
128         c = talloc_zero(mem_ctx, struct dcecli_connection);
129         if (!c) {
130                 return NULL;
131         }
132
133         c->event_ctx = ev;
134
135         if (c->event_ctx == NULL) {
136                 talloc_free(c);
137                 return NULL;
138         }
139
140         c->call_id = 1;
141         c->security_state.auth_info = NULL;
142         c->security_state.session_key = dcerpc_generic_session_key;
143         c->security_state.generic_state = NULL;
144         c->binding_string = NULL;
145         c->flags = 0;
146         c->srv_max_xmit_frag = 0;
147         c->srv_max_recv_frag = 0;
148         c->pending = NULL;
149
150         c->io_trigger = tevent_create_immediate(c);
151         if (c->io_trigger == NULL) {
152                 talloc_free(c);
153                 return NULL;
154         }
155
156         talloc_set_destructor(c, dcerpc_connection_destructor);
157
158         return c;
159 }
160
161 struct dcerpc_bh_state {
162         struct dcerpc_pipe *p;
163 };
164
165 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
166 {
167         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
168                                      struct dcerpc_bh_state);
169
170         if (!hs->p) {
171                 return false;
172         }
173
174         if (!hs->p->conn) {
175                 return false;
176         }
177
178         if (hs->p->conn->dead) {
179                 return false;
180         }
181
182         return true;
183 }
184
185 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
186                                       uint32_t timeout)
187 {
188         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
189                                      struct dcerpc_bh_state);
190         uint32_t old;
191
192         if (!hs->p) {
193                 return DCERPC_REQUEST_TIMEOUT;
194         }
195
196         old = hs->p->request_timeout;
197         hs->p->request_timeout = timeout;
198
199         return old;
200 }
201
202 struct dcerpc_bh_raw_call_state {
203         struct tevent_context *ev;
204         struct dcerpc_binding_handle *h;
205         DATA_BLOB in_data;
206         DATA_BLOB out_data;
207         uint32_t out_flags;
208 };
209
210 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
211
212 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
213                                                   struct tevent_context *ev,
214                                                   struct dcerpc_binding_handle *h,
215                                                   const struct GUID *object,
216                                                   uint32_t opnum,
217                                                   uint32_t in_flags,
218                                                   const uint8_t *in_data,
219                                                   size_t in_length)
220 {
221         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
222                                      struct dcerpc_bh_state);
223         struct tevent_req *req;
224         struct dcerpc_bh_raw_call_state *state;
225         bool ok;
226         struct rpc_request *subreq;
227
228         req = tevent_req_create(mem_ctx, &state,
229                                 struct dcerpc_bh_raw_call_state);
230         if (req == NULL) {
231                 return NULL;
232         }
233         state->ev = ev;
234         state->h = h;
235         state->in_data.data = discard_const_p(uint8_t, in_data);
236         state->in_data.length = in_length;
237
238         ok = dcerpc_bh_is_connected(h);
239         if (!ok) {
240                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
241                 return tevent_req_post(req, ev);
242         }
243
244         subreq = dcerpc_request_send(hs->p,
245                                      object,
246                                      opnum,
247                                      &state->in_data);
248         if (tevent_req_nomem(subreq, req)) {
249                 return tevent_req_post(req, ev);
250         }
251         subreq->async.callback = dcerpc_bh_raw_call_done;
252         subreq->async.private_data = req;
253
254         return req;
255 }
256
257 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
258 {
259         struct tevent_req *req =
260                 talloc_get_type_abort(subreq->async.private_data,
261                 struct tevent_req);
262         struct dcerpc_bh_raw_call_state *state =
263                 tevent_req_data(req,
264                 struct dcerpc_bh_raw_call_state);
265         NTSTATUS status;
266         uint32_t fault_code;
267
268         state->out_flags = 0;
269         if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
270                 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
271         }
272
273         fault_code = subreq->fault_code;
274
275         status = dcerpc_request_recv(subreq, state, &state->out_data);
276         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
277                 status = dcerpc_fault_to_nt_status(fault_code);
278         }
279
280         /*
281          * We trigger the callback in the next event run
282          * because the code in this file might trigger
283          * multiple request callbacks from within a single
284          * while loop.
285          *
286          * In order to avoid segfaults from within
287          * dcerpc_connection_dead() we call
288          * tevent_req_defer_callback().
289          */
290         tevent_req_defer_callback(req, state->ev);
291
292         if (!NT_STATUS_IS_OK(status)) {
293                 tevent_req_nterror(req, status);
294                 return;
295         }
296
297         tevent_req_done(req);
298 }
299
300 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
301                                         TALLOC_CTX *mem_ctx,
302                                         uint8_t **out_data,
303                                         size_t *out_length,
304                                         uint32_t *out_flags)
305 {
306         struct dcerpc_bh_raw_call_state *state =
307                 tevent_req_data(req,
308                 struct dcerpc_bh_raw_call_state);
309         NTSTATUS status;
310
311         if (tevent_req_is_nterror(req, &status)) {
312                 tevent_req_received(req);
313                 return status;
314         }
315
316         *out_data = talloc_move(mem_ctx, &state->out_data.data);
317         *out_length = state->out_data.length;
318         *out_flags = state->out_flags;
319         tevent_req_received(req);
320         return NT_STATUS_OK;
321 }
322
323 struct dcerpc_bh_disconnect_state {
324         uint8_t _dummy;
325 };
326
327 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
328                                                 struct tevent_context *ev,
329                                                 struct dcerpc_binding_handle *h)
330 {
331         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
332                                      struct dcerpc_bh_state);
333         struct tevent_req *req;
334         struct dcerpc_bh_disconnect_state *state;
335         bool ok;
336
337         req = tevent_req_create(mem_ctx, &state,
338                                 struct dcerpc_bh_disconnect_state);
339         if (req == NULL) {
340                 return NULL;
341         }
342
343         ok = dcerpc_bh_is_connected(h);
344         if (!ok) {
345                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
346                 return tevent_req_post(req, ev);
347         }
348
349         /* TODO: do a real disconnect ... */
350         hs->p = NULL;
351
352         tevent_req_done(req);
353         return tevent_req_post(req, ev);
354 }
355
356 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
357 {
358         NTSTATUS status;
359
360         if (tevent_req_is_nterror(req, &status)) {
361                 tevent_req_received(req);
362                 return status;
363         }
364
365         tevent_req_received(req);
366         return NT_STATUS_OK;
367 }
368
369 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
370 {
371         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
372                                      struct dcerpc_bh_state);
373
374         if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
375                 return true;
376         }
377
378         return false;
379 }
380
381 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
382 {
383         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
384                                      struct dcerpc_bh_state);
385
386         if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
387                 return true;
388         }
389
390         return false;
391 }
392
393 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
394 {
395         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
396                                      struct dcerpc_bh_state);
397
398         if (hs->p->conn->flags & DCERPC_NDR64) {
399                 return true;
400         }
401
402         return false;
403 }
404
405 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
406                                    int ndr_flags,
407                                    const void *_struct_ptr,
408                                    const struct ndr_interface_call *call)
409 {
410         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
411                                      struct dcerpc_bh_state);
412         void *struct_ptr = discard_const(_struct_ptr);
413
414         if (ndr_flags & NDR_IN) {
415                 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
416                         ndr_print_function_debug(call->ndr_print,
417                                                  call->name,
418                                                  ndr_flags,
419                                                  struct_ptr);
420                 }
421         }
422         if (ndr_flags & NDR_OUT) {
423                 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
424                         ndr_print_function_debug(call->ndr_print,
425                                                  call->name,
426                                                  ndr_flags,
427                                                  struct_ptr);
428                 }
429         }
430 }
431
432 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
433                                       NTSTATUS error,
434                                       const void *struct_ptr,
435                                       const struct ndr_interface_call *call)
436 {
437         DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
438                  call->name, nt_errstr(error)));
439 }
440
441 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
442                                       NTSTATUS error,
443                                       const DATA_BLOB *blob,
444                                       const struct ndr_interface_call *call)
445 {
446         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
447                                      struct dcerpc_bh_state);
448         const uint32_t num_examples = 20;
449         uint32_t i;
450
451         DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
452                  call->name, nt_errstr(error)));
453
454         if (hs->p->conn->packet_log_dir == NULL) return;
455
456         for (i=0;i<num_examples;i++) {
457                 char *name=NULL;
458                 asprintf(&name, "%s/rpclog/%s-out.%d",
459                          hs->p->conn->packet_log_dir,
460                          call->name, i);
461                 if (name == NULL) {
462                         return;
463                 }
464                 if (!file_exist(name)) {
465                         if (file_save(name, blob->data, blob->length)) {
466                                 DEBUG(10,("Logged rpc packet to %s\n", name));
467                         }
468                         free(name);
469                         break;
470                 }
471                 free(name);
472         }
473 }
474
475 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
476                                           TALLOC_CTX *mem_ctx,
477                                           const DATA_BLOB *blob,
478                                           const struct ndr_interface_call *call)
479 {
480         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
481                                      struct dcerpc_bh_state);
482
483         if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
484                 NTSTATUS status;
485
486                 status = dcerpc_ndr_validate_in(hs->p->conn,
487                                                 mem_ctx,
488                                                 *blob,
489                                                 call->struct_size,
490                                                 call->ndr_push,
491                                                 call->ndr_pull);
492                 if (!NT_STATUS_IS_OK(status)) {
493                         DEBUG(0,("Validation [in] failed for %s - %s\n",
494                                  call->name, nt_errstr(status)));
495                         return status;
496                 }
497         }
498
499         DEBUG(10,("rpc request data:\n"));
500         dump_data(10, blob->data, blob->length);
501
502         return NT_STATUS_OK;
503 }
504
505 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
506                                            struct ndr_pull *pull_in,
507                                            const void *_struct_ptr,
508                                            const struct ndr_interface_call *call)
509 {
510         struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
511                                      struct dcerpc_bh_state);
512         void *struct_ptr = discard_const(_struct_ptr);
513
514         DEBUG(10,("rpc reply data:\n"));
515         dump_data(10, pull_in->data, pull_in->data_size);
516
517         if (pull_in->offset != pull_in->data_size) {
518                 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
519                          pull_in->data_size - pull_in->offset,
520                          pull_in->offset, pull_in->offset,
521                          call->name));
522                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
523                    but it turns out that early versions of NT
524                    (specifically NT3.1) add junk onto the end of rpc
525                    packets, so if we want to interoperate at all with
526                    those versions then we need to ignore this error */
527         }
528
529         if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
530                 NTSTATUS status;
531
532                 status = dcerpc_ndr_validate_out(hs->p->conn,
533                                                  pull_in,
534                                                  struct_ptr,
535                                                  call->struct_size,
536                                                  call->ndr_push,
537                                                  call->ndr_pull,
538                                                  call->ndr_print);
539                 if (!NT_STATUS_IS_OK(status)) {
540                         DEBUG(2,("Validation [out] failed for %s - %s\n",
541                                  call->name, nt_errstr(status)));
542                         return status;
543                 }
544         }
545
546         return NT_STATUS_OK;
547 }
548
549 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
550         .name                   = "dcerpc",
551         .is_connected           = dcerpc_bh_is_connected,
552         .set_timeout            = dcerpc_bh_set_timeout,
553         .raw_call_send          = dcerpc_bh_raw_call_send,
554         .raw_call_recv          = dcerpc_bh_raw_call_recv,
555         .disconnect_send        = dcerpc_bh_disconnect_send,
556         .disconnect_recv        = dcerpc_bh_disconnect_recv,
557
558         .push_bigendian         = dcerpc_bh_push_bigendian,
559         .ref_alloc              = dcerpc_bh_ref_alloc,
560         .use_ndr64              = dcerpc_bh_use_ndr64,
561         .do_ndr_print           = dcerpc_bh_do_ndr_print,
562         .ndr_push_failed        = dcerpc_bh_ndr_push_failed,
563         .ndr_pull_failed        = dcerpc_bh_ndr_pull_failed,
564         .ndr_validate_in        = dcerpc_bh_ndr_validate_in,
565         .ndr_validate_out       = dcerpc_bh_ndr_validate_out,
566 };
567
568 /* initialise a dcerpc pipe. */
569 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
570 {
571         struct dcerpc_binding_handle *h;
572         struct dcerpc_bh_state *hs;
573
574         h = dcerpc_binding_handle_create(p,
575                                          &dcerpc_bh_ops,
576                                          NULL,
577                                          NULL, /* TODO */
578                                          &hs,
579                                          struct dcerpc_bh_state,
580                                          __location__);
581         if (h == NULL) {
582                 return NULL;
583         }
584         hs->p = p;
585
586         dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
587
588         return h;
589 }
590
591 /* initialise a dcerpc pipe. */
592 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
593 {
594         struct dcerpc_pipe *p;
595
596         p = talloc_zero(mem_ctx, struct dcerpc_pipe);
597         if (!p) {
598                 return NULL;
599         }
600
601         p->conn = dcerpc_connection_init(p, ev);
602         if (p->conn == NULL) {
603                 talloc_free(p);
604                 return NULL;
605         }
606
607         p->last_fault_code = 0;
608         p->context_id = 0;
609         p->request_timeout = DCERPC_REQUEST_TIMEOUT;
610         p->binding = NULL;
611
612         ZERO_STRUCT(p->syntax);
613         ZERO_STRUCT(p->transfer_syntax);
614
615         if (DEBUGLVL(100)) {
616                 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
617         }
618
619         p->binding_handle = dcerpc_pipe_binding_handle(p);
620         if (p->binding_handle == NULL) {
621                 talloc_free(p);
622                 return NULL;
623         }
624
625         return p;
626 }
627
628
629 /* 
630    choose the next call id to use
631 */
632 static uint32_t next_call_id(struct dcecli_connection *c)
633 {
634         c->call_id++;
635         if (c->call_id == 0) {
636                 c->call_id++;
637         }
638         return c->call_id;
639 }
640
641 /**
642   setup for a ndr pull, also setting up any flags from the binding string
643 */
644 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c, 
645                                             DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
646 {
647         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
648
649         if (ndr == NULL) return ndr;
650
651         if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
652                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
653         }
654
655         if (c->flags & DCERPC_NDR_REF_ALLOC) {
656                 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
657         }
658
659         if (c->flags & DCERPC_NDR64) {
660                 ndr->flags |= LIBNDR_FLAG_NDR64;
661         }
662
663         return ndr;
664 }
665
666 /* 
667    parse a data blob into a ncacn_packet structure. This handles both
668    input and output packets
669 */
670 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
671                             struct ncacn_packet *pkt)
672 {
673         struct ndr_pull *ndr;
674         enum ndr_err_code ndr_err;
675
676         ndr = ndr_pull_init_flags(c, blob, mem_ctx);
677         if (!ndr) {
678                 return NT_STATUS_NO_MEMORY;
679         }
680
681         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
682                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
683         }
684
685         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
686         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
687                 return ndr_map_error2ntstatus(ndr_err);
688         }
689
690         return NT_STATUS_OK;
691 }
692
693 /* 
694    parse the authentication information on a dcerpc response packet
695 */
696 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx, 
697                                         DATA_BLOB *raw_packet,
698                                         struct ncacn_packet *pkt)
699 {
700         NTSTATUS status;
701         struct dcerpc_auth auth;
702         uint32_t auth_length;
703
704         if (!c->security_state.auth_info ||
705             !c->security_state.generic_state) {
706                 return NT_STATUS_OK;
707         }
708
709         switch (c->security_state.auth_info->auth_level) {
710         case DCERPC_AUTH_LEVEL_PRIVACY:
711         case DCERPC_AUTH_LEVEL_INTEGRITY:
712                 break;
713
714         case DCERPC_AUTH_LEVEL_CONNECT:
715                 if (pkt->auth_length != 0) {
716                         break;
717                 }
718                 return NT_STATUS_OK;
719         case DCERPC_AUTH_LEVEL_NONE:
720                 if (pkt->auth_length != 0) {
721                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
722                 }
723                 return NT_STATUS_OK;
724
725         default:
726                 return NT_STATUS_INVALID_LEVEL;
727         }
728
729         status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
730                                           &pkt->u.response.stub_and_verifier,
731                                           &auth, &auth_length, false);
732         NT_STATUS_NOT_OK_RETURN(status);
733
734         pkt->u.response.stub_and_verifier.length -= auth_length;
735
736         /* check signature or unseal the packet */
737         switch (c->security_state.auth_info->auth_level) {
738         case DCERPC_AUTH_LEVEL_PRIVACY:
739                 status = gensec_unseal_packet(c->security_state.generic_state, 
740                                               raw_packet->data + DCERPC_REQUEST_LENGTH,
741                                               pkt->u.response.stub_and_verifier.length, 
742                                               raw_packet->data,
743                                               raw_packet->length - auth.credentials.length,
744                                               &auth.credentials);
745                 memcpy(pkt->u.response.stub_and_verifier.data,
746                        raw_packet->data + DCERPC_REQUEST_LENGTH,
747                        pkt->u.response.stub_and_verifier.length);
748                 break;
749                 
750         case DCERPC_AUTH_LEVEL_INTEGRITY:
751                 status = gensec_check_packet(c->security_state.generic_state, 
752                                              pkt->u.response.stub_and_verifier.data, 
753                                              pkt->u.response.stub_and_verifier.length, 
754                                              raw_packet->data,
755                                              raw_packet->length - auth.credentials.length,
756                                              &auth.credentials);
757                 break;
758
759         case DCERPC_AUTH_LEVEL_CONNECT:
760                 /* for now we ignore possible signatures here */
761                 status = NT_STATUS_OK;
762                 break;
763
764         default:
765                 status = NT_STATUS_INVALID_LEVEL;
766                 break;
767         }
768         
769         /* remove the indicated amount of padding */
770         if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
771                 return NT_STATUS_INFO_LENGTH_MISMATCH;
772         }
773         pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
774
775         return status;
776 }
777
778
779 /* 
780    push a dcerpc request packet into a blob, possibly signing it.
781 */
782 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c, 
783                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
784                                          size_t sig_size,
785                                          struct ncacn_packet *pkt)
786 {
787         NTSTATUS status;
788         struct ndr_push *ndr;
789         DATA_BLOB creds2;
790         size_t payload_length;
791         enum ndr_err_code ndr_err;
792         size_t hdr_size = DCERPC_REQUEST_LENGTH;
793
794         /* non-signed packets are simpler */
795         if (sig_size == 0) {
796                 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
797         }
798
799         switch (c->security_state.auth_info->auth_level) {
800         case DCERPC_AUTH_LEVEL_PRIVACY:
801         case DCERPC_AUTH_LEVEL_INTEGRITY:
802                 break;
803
804         case DCERPC_AUTH_LEVEL_CONNECT:
805                 /* TODO: let the gensec mech decide if it wants to generate a signature */
806                 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
807
808         case DCERPC_AUTH_LEVEL_NONE:
809                 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
810
811         default:
812                 return NT_STATUS_INVALID_LEVEL;
813         }
814
815         ndr = ndr_push_init_ctx(mem_ctx);
816         if (!ndr) {
817                 return NT_STATUS_NO_MEMORY;
818         }
819
820         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
821                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
822         }
823
824         if (c->flags & DCERPC_NDR64) {
825                 ndr->flags |= LIBNDR_FLAG_NDR64;
826         }
827
828         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
829                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
830                 hdr_size += 16;
831         }
832
833         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
834         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
835                 return ndr_map_error2ntstatus(ndr_err);
836         }
837
838         /* pad to 16 byte multiple in the payload portion of the
839            packet. This matches what w2k3 does. Note that we can't use
840            ndr_push_align() as that is relative to the start of the
841            whole packet, whereas w2k8 wants it relative to the start
842            of the stub */
843         c->security_state.auth_info->auth_pad_length =
844                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
845         ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
846         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
847                 return ndr_map_error2ntstatus(ndr_err);
848         }
849
850         payload_length = pkt->u.request.stub_and_verifier.length + 
851                 c->security_state.auth_info->auth_pad_length;
852
853         /* we start without signature, it will appended later */
854         c->security_state.auth_info->credentials = data_blob(NULL,0);
855
856         /* add the auth verifier */
857         ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
858         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
859                 return ndr_map_error2ntstatus(ndr_err);
860         }
861
862         /* extract the whole packet as a blob */
863         *blob = ndr_push_blob(ndr);
864
865         /*
866          * Setup the frag and auth length in the packet buffer.
867          * This is needed if the GENSEC mech does AEAD signing
868          * of the packet headers. The signature itself will be
869          * appended later.
870          */
871         dcerpc_set_frag_length(blob, blob->length + sig_size);
872         dcerpc_set_auth_length(blob, sig_size);
873
874         /* sign or seal the packet */
875         switch (c->security_state.auth_info->auth_level) {
876         case DCERPC_AUTH_LEVEL_PRIVACY:
877                 status = gensec_seal_packet(c->security_state.generic_state, 
878                                             mem_ctx, 
879                                             blob->data + hdr_size,
880                                             payload_length,
881                                             blob->data,
882                                             blob->length,
883                                             &creds2);
884                 if (!NT_STATUS_IS_OK(status)) {
885                         return status;
886                 }
887                 break;
888
889         case DCERPC_AUTH_LEVEL_INTEGRITY:
890                 status = gensec_sign_packet(c->security_state.generic_state, 
891                                             mem_ctx, 
892                                             blob->data + hdr_size,
893                                             payload_length, 
894                                             blob->data,
895                                             blob->length,
896                                             &creds2);
897                 if (!NT_STATUS_IS_OK(status)) {
898                         return status;
899                 }
900                 break;
901
902         default:
903                 status = NT_STATUS_INVALID_LEVEL;
904                 break;
905         }
906
907         if (creds2.length != sig_size) {
908                 /* this means the sig_size estimate for the signature
909                    was incorrect. We have to correct the packet
910                    sizes. That means we could go over the max fragment
911                    length */
912                 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
913                         (unsigned) creds2.length,
914                         (unsigned) sig_size,
915                         (unsigned) c->security_state.auth_info->auth_pad_length,
916                         (unsigned) pkt->u.request.stub_and_verifier.length));
917                 dcerpc_set_frag_length(blob, blob->length + creds2.length);
918                 dcerpc_set_auth_length(blob, creds2.length);
919         }
920
921         if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
922                 return NT_STATUS_NO_MEMORY;
923         }
924
925         return NT_STATUS_OK;
926 }
927
928
929 /* 
930    fill in the fixed values in a dcerpc header 
931 */
932 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
933 {
934         pkt->rpc_vers = 5;
935         pkt->rpc_vers_minor = 0;
936         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
937                 pkt->drep[0] = 0;
938         } else {
939                 pkt->drep[0] = DCERPC_DREP_LE;
940         }
941         pkt->drep[1] = 0;
942         pkt->drep[2] = 0;
943         pkt->drep[3] = 0;
944 }
945
946 /*
947   map a bind nak reason to a NTSTATUS
948 */
949 static NTSTATUS dcerpc_map_reason(uint16_t reason)
950 {
951         switch (reason) {
952         case DCERPC_BIND_REASON_ASYNTAX:
953                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
954         case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
955                 return NT_STATUS_INVALID_PARAMETER;
956         }
957         return NT_STATUS_UNSUCCESSFUL;
958 }
959
960 /*
961   a bind or alter context has failed
962 */
963 static void dcerpc_composite_fail(struct rpc_request *req)
964 {
965         struct composite_context *c = talloc_get_type(req->async.private_data, 
966                                                       struct composite_context);
967         composite_error(c, req->status);
968 }
969
970 /*
971   remove requests from the pending or queued queues
972  */
973 static int dcerpc_req_dequeue(struct rpc_request *req)
974 {
975         switch (req->state) {
976         case RPC_REQUEST_QUEUED:
977                 DLIST_REMOVE(req->p->conn->request_queue, req);
978                 break;
979         case RPC_REQUEST_PENDING:
980                 DLIST_REMOVE(req->p->conn->pending, req);
981                 break;
982         case RPC_REQUEST_DONE:
983                 break;
984         }
985         return 0;
986 }
987
988
989 /*
990   mark the dcerpc connection dead. All outstanding requests get an error
991 */
992 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
993 {
994         if (conn->dead) return;
995
996         conn->dead = true;
997
998         TALLOC_FREE(conn->io_trigger);
999         conn->io_trigger_pending = false;
1000
1001         conn->transport.recv_data = NULL;
1002
1003         if (conn->transport.shutdown_pipe) {
1004                 conn->transport.shutdown_pipe(conn, status);
1005         }
1006
1007         /* all pending requests get the error */
1008         while (conn->pending) {
1009                 struct rpc_request *req = conn->pending;
1010                 dcerpc_req_dequeue(req);
1011                 req->state = RPC_REQUEST_DONE;
1012                 req->status = status;
1013                 if (req->async.callback) {
1014                         req->async.callback(req);
1015                 }
1016         }       
1017
1018         /* all requests, which are not shipped */
1019         while (conn->request_queue) {
1020                 struct rpc_request *req = conn->request_queue;
1021                 dcerpc_req_dequeue(req);
1022                 req->state = RPC_REQUEST_DONE;
1023                 req->status = status;
1024                 if (req->async.callback) {
1025                         req->async.callback(req);
1026                 }
1027         }
1028
1029         talloc_set_destructor(conn, NULL);
1030         if (conn->free_skipped) {
1031                 talloc_free(conn);
1032         }
1033 }
1034
1035 /*
1036   forward declarations of the recv_data handlers for the types of
1037   packets we need to handle
1038 */
1039 static void dcerpc_request_recv_data(struct dcecli_connection *c, 
1040                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1041
1042 /*
1043   receive a dcerpc reply from the transport. Here we work out what
1044   type of reply it is (normal request, bind or alter context) and
1045   dispatch to the appropriate handler
1046 */
1047 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1048 {
1049         struct ncacn_packet pkt;
1050
1051         if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1052                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1053         }
1054
1055         /* the transport may be telling us of a severe error, such as
1056            a dropped socket */
1057         if (!NT_STATUS_IS_OK(status)) {
1058                 data_blob_free(blob);
1059                 dcerpc_connection_dead(conn, status);
1060                 return;
1061         }
1062
1063         /* parse the basic packet to work out what type of response this is */
1064         status = ncacn_pull(conn, blob, blob->data, &pkt);
1065         if (!NT_STATUS_IS_OK(status)) {
1066                 data_blob_free(blob);
1067                 dcerpc_connection_dead(conn, status);
1068                 return;
1069         }
1070
1071         dcerpc_request_recv_data(conn, blob, &pkt);
1072 }
1073
1074 /*
1075   Receive a bind reply from the transport
1076 */
1077 static void dcerpc_bind_recv_handler(struct rpc_request *req, 
1078                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1079 {
1080         struct composite_context *c;
1081         struct dcecli_connection *conn;
1082
1083         c = talloc_get_type(req->async.private_data, struct composite_context);
1084
1085         if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1086                 DEBUG(2,("dcerpc: bind_nak reason %d\n",
1087                          pkt->u.bind_nak.reject_reason));
1088                 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
1089                                                      reject_reason));
1090                 return;
1091         }
1092
1093         if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1094             (pkt->u.bind_ack.num_results == 0) ||
1095             (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1096                 req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1097                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1098                 return;
1099         }
1100
1101         conn = req->p->conn;
1102
1103         conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1104         conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1105
1106         if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1107             (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1108                 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1109         }
1110
1111         if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1112             (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1113                 conn->flags |= DCERPC_HEADER_SIGNING;
1114         }
1115
1116         /* the bind_ack might contain a reply set of credentials */
1117         if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1118                 NTSTATUS status;
1119                 uint32_t auth_length;
1120                 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1121                                                   conn->security_state.auth_info, &auth_length, true);
1122                 if (!NT_STATUS_IS_OK(status)) {
1123                         composite_error(c, status);
1124                         return;
1125                 }
1126         }
1127
1128         req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1129
1130         composite_done(c);
1131 }
1132
1133 /*
1134   handle timeouts of individual dcerpc requests
1135 */
1136 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
1137                                    struct timeval t, void *private_data)
1138 {
1139         struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1140
1141         if (req->ignore_timeout) {
1142                 dcerpc_req_dequeue(req);
1143                 req->state = RPC_REQUEST_DONE;
1144                 req->status = NT_STATUS_IO_TIMEOUT;
1145                 if (req->async.callback) {
1146                         req->async.callback(req);
1147                 }
1148                 return;
1149         }
1150
1151         dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1152 }
1153
1154 /*
1155   send a async dcerpc bind request
1156 */
1157 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
1158                                            TALLOC_CTX *mem_ctx,
1159                                            const struct ndr_syntax_id *syntax,
1160                                            const struct ndr_syntax_id *transfer_syntax)
1161 {
1162         struct composite_context *c;
1163         struct ncacn_packet pkt;
1164         DATA_BLOB blob;
1165         struct rpc_request *req;
1166
1167         c = composite_create(mem_ctx,p->conn->event_ctx);
1168         if (c == NULL) return NULL;
1169
1170         c->private_data = p;
1171
1172         p->syntax = *syntax;
1173         p->transfer_syntax = *transfer_syntax;
1174
1175         init_ncacn_hdr(p->conn, &pkt);
1176
1177         pkt.ptype = DCERPC_PKT_BIND;
1178         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1179         pkt.call_id = p->conn->call_id;
1180         pkt.auth_length = 0;
1181
1182         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1183                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1184         }
1185
1186         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1187                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1188         }
1189
1190         pkt.u.bind.max_xmit_frag = 5840;
1191         pkt.u.bind.max_recv_frag = 5840;
1192         pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1193         pkt.u.bind.num_contexts = 1;
1194         pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1195         if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
1196         pkt.u.bind.ctx_list[0].context_id = p->context_id;
1197         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1198         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1199         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1200         pkt.u.bind.auth_info = data_blob(NULL, 0);
1201
1202         /* construct the NDR form of the packet */
1203         c->status = ncacn_push_auth(&blob, c, &pkt,
1204                                     p->conn->security_state.auth_info);
1205         if (!composite_is_ok(c)) return c;
1206
1207         p->conn->transport.recv_data = dcerpc_recv_data;
1208
1209         /*
1210          * we allocate a dcerpc_request so we can be in the same
1211          * request queue as normal requests
1212          */
1213         req = talloc_zero(c, struct rpc_request);
1214         if (composite_nomem(req, c)) return c;
1215
1216         req->state = RPC_REQUEST_PENDING;
1217         req->call_id = pkt.call_id;
1218         req->async.private_data = c;
1219         req->async.callback = dcerpc_composite_fail;
1220         req->p = p;
1221         req->recv_handler = dcerpc_bind_recv_handler;
1222         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1223         talloc_set_destructor(req, dcerpc_req_dequeue);
1224
1225         c->status = p->conn->transport.send_request(p->conn, &blob,
1226                                                     true);
1227         if (!composite_is_ok(c)) return c;
1228
1229         tevent_add_timer(c->event_ctx, req,
1230                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1231                         dcerpc_timeout_handler, req);
1232
1233         return c;
1234 }
1235
1236 /*
1237   recv side of async dcerpc bind request
1238 */
1239 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
1240 {
1241         NTSTATUS result = composite_wait(ctx);
1242         talloc_free(ctx);
1243         return result;
1244 }
1245
1246 /* 
1247    perform a continued bind (and auth3)
1248 */
1249 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1250                       TALLOC_CTX *mem_ctx)
1251 {
1252         struct ncacn_packet pkt;
1253         NTSTATUS status;
1254         DATA_BLOB blob;
1255
1256         init_ncacn_hdr(p->conn, &pkt);
1257
1258         pkt.ptype = DCERPC_PKT_AUTH3;
1259         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1260         pkt.call_id = next_call_id(p->conn);
1261         pkt.auth_length = 0;
1262         pkt.u.auth3.auth_info = data_blob(NULL, 0);
1263
1264         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1265                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1266         }
1267
1268         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1269                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1270         }
1271
1272         /* construct the NDR form of the packet */
1273         status = ncacn_push_auth(&blob, mem_ctx,
1274                                  &pkt,
1275                                  p->conn->security_state.auth_info);
1276         if (!NT_STATUS_IS_OK(status)) {
1277                 return status;
1278         }
1279
1280         /* send it on its way */
1281         status = p->conn->transport.send_request(p->conn, &blob, false);
1282         if (!NT_STATUS_IS_OK(status)) {
1283                 return status;
1284         }
1285
1286         return NT_STATUS_OK;    
1287 }
1288
1289
1290 /*
1291   process a fragment received from the transport layer during a
1292   request
1293
1294   This function frees the data 
1295 */
1296 static void dcerpc_request_recv_data(struct dcecli_connection *c, 
1297                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1298 {
1299         struct rpc_request *req;
1300         unsigned int length;
1301         NTSTATUS status = NT_STATUS_OK;
1302
1303         /*
1304           if this is an authenticated connection then parse and check
1305           the auth info. We have to do this before finding the
1306           matching packet, as the request structure might have been
1307           removed due to a timeout, but if it has been we still need
1308           to run the auth routines so that we don't get the sign/seal
1309           info out of step with the server
1310         */
1311         if (c->security_state.auth_info && c->security_state.generic_state &&
1312             pkt->ptype == DCERPC_PKT_RESPONSE) {
1313                 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1314         }
1315
1316         /* find the matching request */
1317         for (req=c->pending;req;req=req->next) {
1318                 if (pkt->call_id == req->call_id) break;
1319         }
1320
1321 #if 0
1322         /* useful for testing certain vendors RPC servers */
1323         if (req == NULL && c->pending && pkt->call_id == 0) {
1324                 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1325                 req = c->pending;
1326         }
1327 #endif
1328
1329         if (req == NULL) {
1330                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1331                 data_blob_free(raw_packet);
1332                 return;
1333         }
1334
1335         talloc_steal(req, raw_packet->data);
1336
1337         if (req->recv_handler != NULL) {
1338                 dcerpc_req_dequeue(req);
1339                 req->state = RPC_REQUEST_DONE;
1340                 req->recv_handler(req, raw_packet, pkt);
1341                 return;
1342         }
1343
1344         if (pkt->ptype == DCERPC_PKT_FAULT) {
1345                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1346                 req->fault_code = pkt->u.fault.status;
1347                 req->status = NT_STATUS_NET_WRITE_FAULT;
1348                 goto req_done;
1349         }
1350
1351         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1352                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1353                          (int)pkt->ptype)); 
1354                 req->fault_code = DCERPC_FAULT_OTHER;
1355                 req->status = NT_STATUS_NET_WRITE_FAULT;
1356                 goto req_done;
1357         }
1358
1359         /* now check the status from the auth routines, and if it failed then fail
1360            this request accordingly */
1361         if (!NT_STATUS_IS_OK(status)) {
1362                 req->status = status;
1363                 goto req_done;
1364         }
1365
1366         length = pkt->u.response.stub_and_verifier.length;
1367
1368         if (length > 0) {
1369                 req->payload.data = talloc_realloc(req, 
1370                                                    req->payload.data, 
1371                                                    uint8_t,
1372                                                    req->payload.length + length);
1373                 if (!req->payload.data) {
1374                         req->status = NT_STATUS_NO_MEMORY;
1375                         goto req_done;
1376                 }
1377                 memcpy(req->payload.data+req->payload.length, 
1378                        pkt->u.response.stub_and_verifier.data, length);
1379                 req->payload.length += length;
1380         }
1381
1382         if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1383                 c->transport.send_read(c);
1384                 return;
1385         }
1386
1387         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1388                 req->flags |= DCERPC_PULL_BIGENDIAN;
1389         } else {
1390                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1391         }
1392
1393
1394 req_done:
1395         /* we've got the full payload */
1396         req->state = RPC_REQUEST_DONE;
1397         DLIST_REMOVE(c->pending, req);
1398
1399         /*
1400          * We have to look at shipping further requests before calling
1401          * the async function, that one might close the pipe
1402          */
1403         dcerpc_schedule_io_trigger(c);
1404
1405         if (req->async.callback) {
1406                 req->async.callback(req);
1407         }
1408 }
1409
1410 /*
1411   perform the send side of a async dcerpc request
1412 */
1413 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
1414                                                const struct GUID *object,
1415                                                uint16_t opnum,
1416                                                DATA_BLOB *stub_data)
1417 {
1418         struct rpc_request *req;
1419
1420         p->conn->transport.recv_data = dcerpc_recv_data;
1421
1422         req = talloc(p, struct rpc_request);
1423         if (req == NULL) {
1424                 return NULL;
1425         }
1426
1427         req->p = p;
1428         req->call_id = next_call_id(p->conn);
1429         req->status = NT_STATUS_OK;
1430         req->state = RPC_REQUEST_QUEUED;
1431         req->payload = data_blob(NULL, 0);
1432         req->flags = 0;
1433         req->fault_code = 0;
1434         req->ignore_timeout = false;
1435         req->async.callback = NULL;
1436         req->async.private_data = NULL;
1437         req->recv_handler = NULL;
1438
1439         if (object != NULL) {
1440                 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1441                 if (req->object == NULL) {
1442                         talloc_free(req);
1443                         return NULL;
1444                 }
1445         } else {
1446                 req->object = NULL;
1447         }
1448
1449         req->opnum = opnum;
1450         req->request_data.length = stub_data->length;
1451         req->request_data.data = talloc_reference(req, stub_data->data);
1452         if (req->request_data.length && req->request_data.data == NULL) {
1453                 return NULL;
1454         }
1455
1456         DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1457         talloc_set_destructor(req, dcerpc_req_dequeue);
1458
1459         dcerpc_schedule_io_trigger(p->conn);
1460
1461         if (p->request_timeout) {
1462                 tevent_add_timer(dcerpc_event_context(p), req,
1463                                 timeval_current_ofs(p->request_timeout, 0), 
1464                                 dcerpc_timeout_handler, req);
1465         }
1466
1467         return req;
1468 }
1469
1470 /*
1471   Send a request using the transport
1472 */
1473
1474 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1475 {
1476         struct rpc_request *req;
1477         struct dcerpc_pipe *p;
1478         DATA_BLOB *stub_data;
1479         struct ncacn_packet pkt;
1480         DATA_BLOB blob;
1481         uint32_t remaining, chunk_size;
1482         bool first_packet = true;
1483         size_t sig_size = 0;
1484         bool need_async = false;
1485
1486         req = c->request_queue;
1487         if (req == NULL) {
1488                 return;
1489         }
1490
1491         p = req->p;
1492         stub_data = &req->request_data;
1493
1494         if (c->pending) {
1495                 need_async = true;
1496         }
1497
1498         DLIST_REMOVE(c->request_queue, req);
1499         DLIST_ADD(c->pending, req);
1500         req->state = RPC_REQUEST_PENDING;
1501
1502         init_ncacn_hdr(p->conn, &pkt);
1503
1504         remaining = stub_data->length;
1505
1506         /* we can write a full max_recv_frag size, minus the dcerpc
1507            request header size */
1508         chunk_size = p->conn->srv_max_recv_frag;
1509         chunk_size -= DCERPC_REQUEST_LENGTH;
1510         if (c->security_state.auth_info &&
1511             c->security_state.generic_state) {
1512                 sig_size = gensec_sig_size(c->security_state.generic_state,
1513                                            p->conn->srv_max_recv_frag);
1514                 if (sig_size) {
1515                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1516                         chunk_size -= sig_size;
1517                 }
1518         }
1519         chunk_size -= (chunk_size % 16);
1520
1521         pkt.ptype = DCERPC_PKT_REQUEST;
1522         pkt.call_id = req->call_id;
1523         pkt.auth_length = 0;
1524         pkt.pfc_flags = 0;
1525         pkt.u.request.alloc_hint = remaining;
1526         pkt.u.request.context_id = p->context_id;
1527         pkt.u.request.opnum = req->opnum;
1528
1529         if (req->object) {
1530                 pkt.u.request.object.object = *req->object;
1531                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1532                 chunk_size -= ndr_size_GUID(req->object,0);
1533         }
1534
1535         /* we send a series of pdus without waiting for a reply */
1536         while (remaining > 0 || first_packet) {
1537                 uint32_t chunk = MIN(chunk_size, remaining);
1538                 bool last_frag = false;
1539                 bool do_trans = false;
1540
1541                 first_packet = false;
1542                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1543
1544                 if (remaining == stub_data->length) {
1545                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1546                 }
1547                 if (chunk == remaining) {
1548                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1549                         last_frag = true;
1550                 }
1551
1552                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1553                         (stub_data->length - remaining);
1554                 pkt.u.request.stub_and_verifier.length = chunk;
1555
1556                 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1557                 if (!NT_STATUS_IS_OK(req->status)) {
1558                         req->state = RPC_REQUEST_DONE;
1559                         DLIST_REMOVE(p->conn->pending, req);
1560                         return;
1561                 }
1562
1563                 if (last_frag && !need_async) {
1564                         do_trans = true;
1565                 }
1566
1567                 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1568                 if (!NT_STATUS_IS_OK(req->status)) {
1569                         req->state = RPC_REQUEST_DONE;
1570                         DLIST_REMOVE(p->conn->pending, req);
1571                         return;
1572                 }               
1573
1574                 if (last_frag && !do_trans) {
1575                         req->status = p->conn->transport.send_read(p->conn);
1576                         if (!NT_STATUS_IS_OK(req->status)) {
1577                                 req->state = RPC_REQUEST_DONE;
1578                                 DLIST_REMOVE(p->conn->pending, req);
1579                                 return;
1580                         }
1581                 }
1582
1583                 remaining -= chunk;
1584         }
1585 }
1586
1587 static void dcerpc_io_trigger(struct tevent_context *ctx,
1588                               struct tevent_immediate *im,
1589                               void *private_data)
1590 {
1591         struct dcecli_connection *c =
1592                 talloc_get_type_abort(private_data,
1593                 struct dcecli_connection);
1594
1595         c->io_trigger_pending = false;
1596
1597         dcerpc_schedule_io_trigger(c);
1598
1599         dcerpc_ship_next_request(c);
1600 }
1601
1602 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1603 {
1604         if (c->dead) {
1605                 return;
1606         }
1607
1608         if (c->request_queue == NULL) {
1609                 return;
1610         }
1611
1612         if (c->io_trigger_pending) {
1613                 return;
1614         }
1615
1616         c->io_trigger_pending = true;
1617
1618         tevent_schedule_immediate(c->io_trigger,
1619                                   c->event_ctx,
1620                                   dcerpc_io_trigger,
1621                                   c);
1622 }
1623
1624 /*
1625   return the event context for a dcerpc pipe
1626   used by callers who wish to operate asynchronously
1627 */
1628 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1629 {
1630         return p->conn->event_ctx;
1631 }
1632
1633
1634
1635 /*
1636   perform the receive side of a async dcerpc request
1637 */
1638 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1639                                     TALLOC_CTX *mem_ctx,
1640                                     DATA_BLOB *stub_data)
1641 {
1642         NTSTATUS status;
1643
1644         while (req->state != RPC_REQUEST_DONE) {
1645                 struct tevent_context *ctx = dcerpc_event_context(req->p);
1646                 if (tevent_loop_once(ctx) != 0) {
1647                         return NT_STATUS_CONNECTION_DISCONNECTED;
1648                 }
1649         }
1650         *stub_data = req->payload;
1651         status = req->status;
1652         if (stub_data->data) {
1653                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1654         }
1655         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1656                 req->p->last_fault_code = req->fault_code;
1657         }
1658         talloc_unlink(talloc_parent(req), req);
1659         return status;
1660 }
1661
1662 /*
1663   this is a paranoid NDR validator. For every packet we push onto the wire
1664   we pull it back again, then push it again. Then we compare the raw NDR data
1665   for that to the NDR we initially generated. If they don't match then we know
1666   we must have a bug in either the pull or push side of our code
1667 */
1668 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c, 
1669                                        TALLOC_CTX *mem_ctx,
1670                                        DATA_BLOB blob,
1671                                        size_t struct_size,
1672                                        ndr_push_flags_fn_t ndr_push,
1673                                        ndr_pull_flags_fn_t ndr_pull)
1674 {
1675         void *st;
1676         struct ndr_pull *pull;
1677         struct ndr_push *push;
1678         DATA_BLOB blob2;
1679         enum ndr_err_code ndr_err;
1680
1681         st = talloc_size(mem_ctx, struct_size);
1682         if (!st) {
1683                 return NT_STATUS_NO_MEMORY;
1684         }
1685
1686         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1687         if (!pull) {
1688                 return NT_STATUS_NO_MEMORY;
1689         }
1690         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1691
1692         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1693                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1694         }
1695
1696         if (c->flags & DCERPC_NDR64) {
1697                 pull->flags |= LIBNDR_FLAG_NDR64;
1698         }
1699
1700         ndr_err = ndr_pull(pull, NDR_IN, st);
1701         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1702                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1703                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1704                                          "failed input validation pull - %s",
1705                                          nt_errstr(status));
1706                 return ndr_map_error2ntstatus(ndr_err);
1707         }
1708
1709         push = ndr_push_init_ctx(mem_ctx);
1710         if (!push) {
1711                 return NT_STATUS_NO_MEMORY;
1712         }       
1713
1714         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1715                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1716         }
1717
1718         if (c->flags & DCERPC_NDR64) {
1719                 push->flags |= LIBNDR_FLAG_NDR64;
1720         }
1721
1722         ndr_err = ndr_push(push, NDR_IN, st);
1723         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1724                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1725                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1726                                          "failed input validation push - %s",
1727                                          nt_errstr(status));
1728                 return ndr_map_error2ntstatus(ndr_err);
1729         }
1730
1731         blob2 = ndr_push_blob(push);
1732
1733         if (data_blob_cmp(&blob, &blob2) != 0) {
1734                 DEBUG(3,("original:\n"));
1735                 dump_data(3, blob.data, blob.length);
1736                 DEBUG(3,("secondary:\n"));
1737                 dump_data(3, blob2.data, blob2.length);
1738                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1739                                          "failed input validation blobs doesn't match");
1740                 return ndr_map_error2ntstatus(ndr_err);
1741         }
1742
1743         return NT_STATUS_OK;
1744 }
1745
1746 /*
1747   this is a paranoid NDR input validator. For every packet we pull
1748   from the wire we push it back again then pull and push it
1749   again. Then we compare the raw NDR data for that to the NDR we
1750   initially generated. If they don't match then we know we must have a
1751   bug in either the pull or push side of our code
1752 */
1753 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1754                                         struct ndr_pull *pull_in,
1755                                         void *struct_ptr,
1756                                         size_t struct_size,
1757                                         ndr_push_flags_fn_t ndr_push,
1758                                         ndr_pull_flags_fn_t ndr_pull,
1759                                         ndr_print_function_t ndr_print)
1760 {
1761         void *st;
1762         struct ndr_pull *pull;
1763         struct ndr_push *push;
1764         DATA_BLOB blob, blob2;
1765         TALLOC_CTX *mem_ctx = pull_in;
1766         char *s1, *s2;
1767         enum ndr_err_code ndr_err;
1768
1769         st = talloc_size(mem_ctx, struct_size);
1770         if (!st) {
1771                 return NT_STATUS_NO_MEMORY;
1772         }
1773         memcpy(st, struct_ptr, struct_size);
1774
1775         push = ndr_push_init_ctx(mem_ctx);
1776         if (!push) {
1777                 return NT_STATUS_NO_MEMORY;
1778         }       
1779
1780         ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1781         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1782                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1783                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1784                                          "failed output validation push - %s",
1785                                          nt_errstr(status));
1786                 return ndr_map_error2ntstatus(ndr_err);
1787         }
1788
1789         blob = ndr_push_blob(push);
1790
1791         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1792         if (!pull) {
1793                 return NT_STATUS_NO_MEMORY;
1794         }
1795
1796         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1797         ndr_err = ndr_pull(pull, NDR_OUT, st);
1798         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1799                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1800                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1801                                          "failed output validation pull - %s",
1802                                          nt_errstr(status));
1803                 return ndr_map_error2ntstatus(ndr_err);
1804         }
1805
1806         push = ndr_push_init_ctx(mem_ctx);
1807         if (!push) {
1808                 return NT_STATUS_NO_MEMORY;
1809         }       
1810
1811         ndr_err = ndr_push(push, NDR_OUT, st);
1812         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1813                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1814                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1815                                          "failed output validation push2 - %s",
1816                                          nt_errstr(status));
1817                 return ndr_map_error2ntstatus(ndr_err);
1818         }
1819
1820         blob2 = ndr_push_blob(push);
1821
1822         if (data_blob_cmp(&blob, &blob2) != 0) {
1823                 DEBUG(3,("original:\n"));
1824                 dump_data(3, blob.data, blob.length);
1825                 DEBUG(3,("secondary:\n"));
1826                 dump_data(3, blob2.data, blob2.length);
1827                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1828                                          "failed output validation blobs doesn't match");
1829                 return ndr_map_error2ntstatus(ndr_err);
1830         }
1831
1832         /* this checks the printed forms of the two structures, which effectively
1833            tests all of the value() attributes */
1834         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1835                                        NDR_OUT, struct_ptr);
1836         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1837                                        NDR_OUT, st);
1838         if (strcmp(s1, s2) != 0) {
1839 #if 1
1840                 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1841 #else
1842                 /* this is sometimes useful */
1843                 printf("VALIDATE ERROR\n");
1844                 file_save("wire.dat", s1, strlen(s1));
1845                 file_save("gen.dat", s2, strlen(s2));
1846                 system("diff -u wire.dat gen.dat");
1847 #endif
1848                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1849                                          "failed output validation strings doesn't match");
1850                 return ndr_map_error2ntstatus(ndr_err);
1851         }
1852
1853         return NT_STATUS_OK;
1854 }
1855
1856 /*
1857   a useful function for retrieving the server name we connected to
1858 */
1859 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1860 {
1861         if (!p->conn->transport.target_hostname) {
1862                 if (!p->conn->transport.peer_name) {
1863                         return "";
1864                 }
1865                 return p->conn->transport.peer_name(p->conn);
1866         }
1867         return p->conn->transport.target_hostname(p->conn);
1868 }
1869
1870
1871 /*
1872   get the dcerpc auth_level for a open connection
1873 */
1874 uint32_t dcerpc_auth_level(struct dcecli_connection *c) 
1875 {
1876         uint8_t auth_level;
1877
1878         if (c->flags & DCERPC_SEAL) {
1879                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1880         } else if (c->flags & DCERPC_SIGN) {
1881                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1882         } else if (c->flags & DCERPC_CONNECT) {
1883                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1884         } else {
1885                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1886         }
1887         return auth_level;
1888 }
1889
1890 /*
1891   Receive an alter reply from the transport
1892 */
1893 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1894                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1895 {
1896         struct composite_context *c;
1897         struct dcerpc_pipe *recv_pipe;
1898
1899         c = talloc_get_type(req->async.private_data, struct composite_context);
1900         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1901
1902         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1903             pkt->u.alter_resp.num_results == 1 &&
1904             pkt->u.alter_resp.ctx_list[0].result != 0) {
1905                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1906                          pkt->u.alter_resp.ctx_list[0].reason));
1907                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1908                 return;
1909         }
1910
1911         if (pkt->ptype == DCERPC_PKT_FAULT) {
1912                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1913                 recv_pipe->last_fault_code = pkt->u.fault.status;
1914                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1915                 return;
1916         }
1917
1918         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1919             pkt->u.alter_resp.num_results == 0 ||
1920             pkt->u.alter_resp.ctx_list[0].result != 0) {
1921                 recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1922                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1923                 return;
1924         }
1925
1926         /* the alter_resp might contain a reply set of credentials */
1927         if (recv_pipe->conn->security_state.auth_info &&
1928             pkt->u.alter_resp.auth_info.length) {
1929                 struct dcecli_connection *conn = recv_pipe->conn;
1930                 NTSTATUS status;
1931                 uint32_t auth_length;
1932                 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1933                                                   conn->security_state.auth_info, &auth_length, true);
1934                 if (!NT_STATUS_IS_OK(status)) {
1935                         composite_error(c, status);
1936                         return;
1937                 }
1938         }
1939
1940         composite_done(c);
1941 }
1942
1943 /* 
1944    send a dcerpc alter_context request
1945 */
1946 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1947                                                     TALLOC_CTX *mem_ctx,
1948                                                     const struct ndr_syntax_id *syntax,
1949                                                     const struct ndr_syntax_id *transfer_syntax)
1950 {
1951         struct composite_context *c;
1952         struct ncacn_packet pkt;
1953         DATA_BLOB blob;
1954         struct rpc_request *req;
1955
1956         c = composite_create(mem_ctx, p->conn->event_ctx);
1957         if (c == NULL) return NULL;
1958
1959         c->private_data = p;
1960
1961         p->syntax = *syntax;
1962         p->transfer_syntax = *transfer_syntax;
1963
1964         init_ncacn_hdr(p->conn, &pkt);
1965
1966         pkt.ptype = DCERPC_PKT_ALTER;
1967         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1968         pkt.call_id = p->conn->call_id;
1969         pkt.auth_length = 0;
1970
1971         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1972                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1973         }
1974
1975         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1976                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1977         }
1978
1979         pkt.u.alter.max_xmit_frag = 5840;
1980         pkt.u.alter.max_recv_frag = 5840;
1981         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1982         pkt.u.alter.num_contexts = 1;
1983         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1984         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1985         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1986         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1987         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1988         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1989         pkt.u.alter.auth_info = data_blob(NULL, 0);
1990
1991         /* construct the NDR form of the packet */
1992         c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1993                                     p->conn->security_state.auth_info);
1994         if (!composite_is_ok(c)) return c;
1995
1996         p->conn->transport.recv_data = dcerpc_recv_data;
1997
1998         /*
1999          * we allocate a dcerpc_request so we can be in the same
2000          * request queue as normal requests
2001          */
2002         req = talloc_zero(c, struct rpc_request);
2003         if (composite_nomem(req, c)) return c;
2004
2005         req->state = RPC_REQUEST_PENDING;
2006         req->call_id = pkt.call_id;
2007         req->async.private_data = c;
2008         req->async.callback = dcerpc_composite_fail;
2009         req->p = p;
2010         req->recv_handler = dcerpc_alter_recv_handler;
2011         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
2012         talloc_set_destructor(req, dcerpc_req_dequeue);
2013
2014         c->status = p->conn->transport.send_request(p->conn, &blob, true);
2015         if (!composite_is_ok(c)) return c;
2016
2017         tevent_add_timer(c->event_ctx, req,
2018                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2019                         dcerpc_timeout_handler, req);
2020
2021         return c;
2022 }
2023
2024 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
2025 {
2026         NTSTATUS result = composite_wait(ctx);
2027         talloc_free(ctx);
2028         return result;
2029 }
2030
2031 /* 
2032    send a dcerpc alter_context request
2033 */
2034 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
2035                               TALLOC_CTX *mem_ctx,
2036                               const struct ndr_syntax_id *syntax,
2037                               const struct ndr_syntax_id *transfer_syntax)
2038 {
2039         struct composite_context *creq;
2040         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
2041         return dcerpc_alter_context_recv(creq);
2042 }
2043