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