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