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