r21811: fixed a queueing error in the dcerpc client code. WHen the
[jra/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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.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
33 NTSTATUS dcerpc_init(void)
34 {
35         gensec_init();
36
37         return NT_STATUS_OK;
38 }
39
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
41
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *c)
44 {
45         if (c->transport.shutdown_pipe) {
46                 c->transport.shutdown_pipe(c);
47         }
48         return 0;
49 }
50
51
52 /* initialise a dcerpc connection. 
53    the event context is optional
54 */
55 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
56                                                  struct event_context *ev)
57 {
58         struct dcerpc_connection *c;
59
60         c = talloc_zero(mem_ctx, struct dcerpc_connection);
61         if (!c) {
62                 return NULL;
63         }
64
65         if (ev == NULL) {
66                 ev = event_context_init(c);
67                 if (ev == NULL) {
68                         talloc_free(c);
69                         return NULL;
70                 }
71         }
72
73         c->event_ctx = ev;
74         
75         if (!talloc_reference(c, ev)) {
76                 talloc_free(c);
77                 return NULL;
78         }
79         c->call_id = 1;
80         c->security_state.auth_info = NULL;
81         c->security_state.session_key = dcerpc_generic_session_key;
82         c->security_state.generic_state = NULL;
83         c->binding_string = NULL;
84         c->flags = 0;
85         c->srv_max_xmit_frag = 0;
86         c->srv_max_recv_frag = 0;
87         c->pending = NULL;
88
89         talloc_set_destructor(c, dcerpc_connection_destructor);
90
91         return c;
92 }
93
94 /* initialise a dcerpc pipe. */
95 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
96 {
97         struct dcerpc_pipe *p;
98
99         p = talloc(mem_ctx, struct dcerpc_pipe);
100         if (!p) {
101                 return NULL;
102         }
103
104         p->conn = dcerpc_connection_init(p, ev);
105         if (p->conn == NULL) {
106                 talloc_free(p);
107                 return NULL;
108         }
109
110         p->last_fault_code = 0;
111         p->context_id = 0;
112         p->request_timeout = DCERPC_REQUEST_TIMEOUT;
113         p->binding = NULL;
114
115         ZERO_STRUCT(p->syntax);
116         ZERO_STRUCT(p->transfer_syntax);
117
118         return p;
119 }
120
121
122 /* 
123    choose the next call id to use
124 */
125 static uint32_t next_call_id(struct dcerpc_connection *c)
126 {
127         c->call_id++;
128         if (c->call_id == 0) {
129                 c->call_id++;
130         }
131         return c->call_id;
132 }
133
134 /* we need to be able to get/set the fragment length without doing a full
135    decode */
136 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
137 {
138         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
139                 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
140         } else {
141                 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
142         }
143 }
144
145 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
146 {
147         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
148                 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
149         } else {
150                 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
151         }
152 }
153
154 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
155 {
156         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
157                 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
158         } else {
159                 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
160         }
161 }
162
163
164 /*
165   setup for a ndr pull, also setting up any flags from the binding string
166 */
167 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c, 
168                                             DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
169 {
170         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
171
172         if (ndr == NULL) return ndr;
173
174         if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
175                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
176         }
177
178         if (c->flags & DCERPC_NDR_REF_ALLOC) {
179                 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
180         }
181
182         return ndr;
183 }
184
185 /* 
186    parse a data blob into a ncacn_packet structure. This handles both
187    input and output packets
188 */
189 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
190                             struct ncacn_packet *pkt)
191 {
192         struct ndr_pull *ndr;
193
194         ndr = ndr_pull_init_flags(c, blob, mem_ctx);
195         if (!ndr) {
196                 return NT_STATUS_NO_MEMORY;
197         }
198
199         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
200                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
201         }
202
203         return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
204 }
205
206 /*
207   generate a CONNECT level verifier
208 */
209 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
210 {
211         *blob = data_blob_talloc(mem_ctx, NULL, 16);
212         if (blob->data == NULL) {
213                 return NT_STATUS_NO_MEMORY;
214         }
215         SIVAL(blob->data, 0, 1);
216         memset(blob->data+4, 0, 12);
217         return NT_STATUS_OK;
218 }
219
220 /*
221   check a CONNECT level verifier
222 */
223 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
224 {
225         if (blob->length != 16 ||
226             IVAL(blob->data, 0) != 1) {
227                 return NT_STATUS_ACCESS_DENIED;
228         }
229         return NT_STATUS_OK;
230 }
231
232 /* 
233    parse the authentication information on a dcerpc response packet
234 */
235 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx, 
236                                         DATA_BLOB *raw_packet,
237                                         struct ncacn_packet *pkt)
238 {
239         struct ndr_pull *ndr;
240         NTSTATUS status;
241         struct dcerpc_auth auth;
242         DATA_BLOB auth_blob;
243
244         if (pkt->auth_length == 0 &&
245             c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
246                 return NT_STATUS_OK;
247         }
248
249         auth_blob.length = 8 + pkt->auth_length;
250
251         /* check for a valid length */
252         if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
253                 return NT_STATUS_INFO_LENGTH_MISMATCH;
254         }
255
256         auth_blob.data = 
257                 pkt->u.response.stub_and_verifier.data + 
258                 pkt->u.response.stub_and_verifier.length - auth_blob.length;
259         pkt->u.response.stub_and_verifier.length -= auth_blob.length;
260
261         /* pull the auth structure */
262         ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
263         if (!ndr) {
264                 return NT_STATUS_NO_MEMORY;
265         }
266
267         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
268                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
269         }
270
271         status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
272         if (!NT_STATUS_IS_OK(status)) {
273                 return status;
274         }
275         
276         /* check signature or unseal the packet */
277         switch (c->security_state.auth_info->auth_level) {
278         case DCERPC_AUTH_LEVEL_PRIVACY:
279                 status = gensec_unseal_packet(c->security_state.generic_state, 
280                                               mem_ctx, 
281                                               raw_packet->data + DCERPC_REQUEST_LENGTH,
282                                               pkt->u.response.stub_and_verifier.length, 
283                                               raw_packet->data,
284                                               raw_packet->length - auth.credentials.length,
285                                               &auth.credentials);
286                 memcpy(pkt->u.response.stub_and_verifier.data,
287                        raw_packet->data + DCERPC_REQUEST_LENGTH,
288                        pkt->u.response.stub_and_verifier.length);
289                 break;
290                 
291         case DCERPC_AUTH_LEVEL_INTEGRITY:
292                 status = gensec_check_packet(c->security_state.generic_state, 
293                                              mem_ctx, 
294                                              pkt->u.response.stub_and_verifier.data, 
295                                              pkt->u.response.stub_and_verifier.length, 
296                                              raw_packet->data,
297                                              raw_packet->length - auth.credentials.length,
298                                              &auth.credentials);
299                 break;
300
301         case DCERPC_AUTH_LEVEL_CONNECT:
302                 status = dcerpc_check_connect_verifier(&auth.credentials);
303                 break;
304
305         case DCERPC_AUTH_LEVEL_NONE:
306                 break;
307
308         default:
309                 status = NT_STATUS_INVALID_LEVEL;
310                 break;
311         }
312         
313         /* remove the indicated amount of paddiing */
314         if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
315                 return NT_STATUS_INFO_LENGTH_MISMATCH;
316         }
317         pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
318
319         return status;
320 }
321
322
323 /* 
324    push a dcerpc request packet into a blob, possibly signing it.
325 */
326 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, 
327                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
328                                          struct ncacn_packet *pkt)
329 {
330         NTSTATUS status;
331         struct ndr_push *ndr;
332         DATA_BLOB creds2;
333         size_t payload_length;
334
335         /* non-signed packets are simpler */
336         if (!c->security_state.auth_info || 
337             !c->security_state.generic_state) {
338                 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
339         }
340
341         ndr = ndr_push_init_ctx(mem_ctx);
342         if (!ndr) {
343                 return NT_STATUS_NO_MEMORY;
344         }
345
346         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
347                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
348         }
349
350         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
351                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
352         }
353
354         status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
355         if (!NT_STATUS_IS_OK(status)) {
356                 return status;
357         }
358
359         /* pad to 16 byte multiple in the payload portion of the
360            packet. This matches what w2k3 does */
361         c->security_state.auth_info->auth_pad_length = 
362                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
363         ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
364
365         payload_length = pkt->u.request.stub_and_verifier.length + 
366                 c->security_state.auth_info->auth_pad_length;
367
368         /* sign or seal the packet */
369         switch (c->security_state.auth_info->auth_level) {
370         case DCERPC_AUTH_LEVEL_PRIVACY:
371         case DCERPC_AUTH_LEVEL_INTEGRITY:
372                 /* We hope this length is accruate.  If must be if the
373                  * GENSEC mech does AEAD signing of the packet
374                  * headers */
375                 c->security_state.auth_info->credentials
376                         = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state, 
377                                                                           payload_length));
378                 data_blob_clear(&c->security_state.auth_info->credentials);
379                 break;
380
381         case DCERPC_AUTH_LEVEL_CONNECT:
382                 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
383                 break;
384                 
385         case DCERPC_AUTH_LEVEL_NONE:
386                 c->security_state.auth_info->credentials = data_blob(NULL, 0);
387                 break;
388                 
389         default:
390                 status = NT_STATUS_INVALID_LEVEL;
391                 break;
392         }
393         
394         if (!NT_STATUS_IS_OK(status)) {
395                 return status;
396         }       
397
398         /* add the auth verifier */
399         status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
400         if (!NT_STATUS_IS_OK(status)) {
401                 return status;
402         }
403
404         /* extract the whole packet as a blob */
405         *blob = ndr_push_blob(ndr);
406
407         /* fill in the fragment length and auth_length, we can't fill
408            in these earlier as we don't know the signature length (it
409            could be variable length) */
410         dcerpc_set_frag_length(blob, blob->length);
411         /* We hope this value is accruate.  If must be if the GENSEC
412          * mech does AEAD signing of the packet headers */
413         dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
414
415         /* sign or seal the packet */
416         switch (c->security_state.auth_info->auth_level) {
417         case DCERPC_AUTH_LEVEL_PRIVACY:
418                 status = gensec_seal_packet(c->security_state.generic_state, 
419                                             mem_ctx, 
420                                             blob->data + DCERPC_REQUEST_LENGTH, 
421                                             payload_length,
422                                             blob->data,
423                                             blob->length - 
424                                             c->security_state.auth_info->credentials.length,
425                                             &creds2);
426                 if (!NT_STATUS_IS_OK(status)) {
427                         return status;
428                 }
429                 blob->length -= c->security_state.auth_info->credentials.length;
430                 status = data_blob_append(mem_ctx, blob,
431                                           creds2.data, creds2.length);
432                 if (!NT_STATUS_IS_OK(status)) {
433                         return status;
434                 }
435                 dcerpc_set_auth_length(blob, creds2.length);
436                 if (c->security_state.auth_info->credentials.length == 0) {
437                         /* this is needed for krb5 only, to correct the total packet
438                            length */
439                         dcerpc_set_frag_length(blob, 
440                                                dcerpc_get_frag_length(blob)
441                                                +creds2.length);
442                 }
443                 break;
444
445         case DCERPC_AUTH_LEVEL_INTEGRITY:
446                 status = gensec_sign_packet(c->security_state.generic_state, 
447                                             mem_ctx, 
448                                             blob->data + DCERPC_REQUEST_LENGTH, 
449                                             payload_length, 
450                                             blob->data,
451                                             blob->length - 
452                                             c->security_state.auth_info->credentials.length,
453                                             &creds2);
454                 if (!NT_STATUS_IS_OK(status)) {
455                         return status;
456                 }
457                 blob->length -= c->security_state.auth_info->credentials.length;
458                 status = data_blob_append(mem_ctx, blob,
459                                           creds2.data, creds2.length);
460                 if (!NT_STATUS_IS_OK(status)) {
461                         return status;
462                 }
463                 dcerpc_set_auth_length(blob, creds2.length);
464                 if (c->security_state.auth_info->credentials.length == 0) {
465                         /* this is needed for krb5 only, to correct the total packet
466                            length */
467                         dcerpc_set_frag_length(blob, 
468                                                dcerpc_get_frag_length(blob)
469                                                +creds2.length);
470                 }
471                 break;
472
473         case DCERPC_AUTH_LEVEL_CONNECT:
474                 break;
475
476         case DCERPC_AUTH_LEVEL_NONE:
477                 c->security_state.auth_info->credentials = data_blob(NULL, 0);
478                 break;
479
480         default:
481                 status = NT_STATUS_INVALID_LEVEL;
482                 break;
483         }
484
485         data_blob_free(&c->security_state.auth_info->credentials);
486
487         return NT_STATUS_OK;
488 }
489
490
491 /* 
492    fill in the fixed values in a dcerpc header 
493 */
494 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
495 {
496         pkt->rpc_vers = 5;
497         pkt->rpc_vers_minor = 0;
498         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
499                 pkt->drep[0] = 0;
500         } else {
501                 pkt->drep[0] = DCERPC_DREP_LE;
502         }
503         pkt->drep[1] = 0;
504         pkt->drep[2] = 0;
505         pkt->drep[3] = 0;
506 }
507
508 /*
509   map a bind nak reason to a NTSTATUS
510 */
511 static NTSTATUS dcerpc_map_reason(uint16_t reason)
512 {
513         switch (reason) {
514         case DCERPC_BIND_REASON_ASYNTAX:
515                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
516         case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
517                 return NT_STATUS_INVALID_PARAMETER;
518         }
519         return NT_STATUS_UNSUCCESSFUL;
520 }
521
522 /*
523   a bind or alter context has failed
524 */
525 static void dcerpc_composite_fail(struct rpc_request *req)
526 {
527         struct composite_context *c = talloc_get_type(req->async.private, 
528                                                       struct composite_context);
529         composite_error(c, req->status);
530 }
531
532 /*
533   remove requests from the pending or queued queues
534  */
535 static int dcerpc_req_dequeue(struct rpc_request *req)
536 {
537         switch (req->state) {
538         case RPC_REQUEST_QUEUED:
539                 DLIST_REMOVE(req->p->conn->request_queue, req);
540                 break;
541         case RPC_REQUEST_PENDING:
542                 DLIST_REMOVE(req->p->conn->pending, req);
543                 break;
544         case RPC_REQUEST_DONE:
545                 break;
546         }
547         return 0;
548 }
549
550
551 /*
552   mark the dcerpc connection dead. All outstanding requests get an error
553 */
554 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
555 {
556         /* all pending requests get the error */
557         while (conn->pending) {
558                 struct rpc_request *req = conn->pending;
559                 dcerpc_req_dequeue(req);
560                 req->state = RPC_REQUEST_DONE;
561                 req->status = status;
562                 if (req->async.callback) {
563                         req->async.callback(req);
564                 }
565         }       
566 }
567
568 /*
569   forward declarations of the recv_data handlers for the types of
570   packets we need to handle
571 */
572 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
573                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
574
575 /*
576   receive a dcerpc reply from the transport. Here we work out what
577   type of reply it is (normal request, bind or alter context) and
578   dispatch to the appropriate handler
579 */
580 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
581 {
582         struct ncacn_packet pkt;
583
584         if (NT_STATUS_IS_OK(status) && blob->length == 0) {
585                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
586         }
587
588         /* the transport may be telling us of a severe error, such as
589            a dropped socket */
590         if (!NT_STATUS_IS_OK(status)) {
591                 data_blob_free(blob);
592                 dcerpc_connection_dead(conn, status);
593                 return;
594         }
595
596         /* parse the basic packet to work out what type of response this is */
597         status = ncacn_pull(conn, blob, blob->data, &pkt);
598         if (!NT_STATUS_IS_OK(status)) {
599                 data_blob_free(blob);
600                 dcerpc_connection_dead(conn, status);
601         }
602
603         dcerpc_request_recv_data(conn, blob, &pkt);
604 }
605
606
607 /*
608   Receive a bind reply from the transport
609 */
610 static void dcerpc_bind_recv_handler(struct rpc_request *req, 
611                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
612 {
613         struct composite_context *c;
614         struct dcerpc_connection *conn;
615
616         c = talloc_get_type(req->async.private, struct composite_context);
617
618         if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
619                 DEBUG(2,("dcerpc: bind_nak reason %d\n",
620                          pkt->u.bind_nak.reject_reason));
621                 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
622                                                      reject_reason));
623                 return;
624         }
625
626         if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
627             (pkt->u.bind_ack.num_results == 0) ||
628             (pkt->u.bind_ack.ctx_list[0].result != 0)) {
629                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
630                 return;
631         }
632
633         conn = req->p->conn;
634
635         conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
636         conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
637
638         /* the bind_ack might contain a reply set of credentials */
639         if (conn->security_state.auth_info &&
640             pkt->u.bind_ack.auth_info.length) {
641                 c->status = ndr_pull_struct_blob(
642                         &pkt->u.bind_ack.auth_info, conn,
643                         conn->security_state.auth_info,
644                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
645                 if (!composite_is_ok(c)) return;
646         }
647
648         req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
649
650         composite_done(c);
651 }
652
653 /*
654   handle timeouts of individual dcerpc requests
655 */
656 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te, 
657                                    struct timeval t, void *private)
658 {
659         struct rpc_request *req = talloc_get_type(private, struct rpc_request);
660
661         if (req->state == RPC_REQUEST_DONE) {
662                 return;
663         }
664
665         dcerpc_req_dequeue(req);
666
667         req->status = NT_STATUS_IO_TIMEOUT;
668         req->state = RPC_REQUEST_DONE;
669         if (req->async.callback) {
670                 req->async.callback(req);
671         }
672 }
673
674 /*
675   send a async dcerpc bind request
676 */
677 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
678                                            TALLOC_CTX *mem_ctx,
679                                            const struct dcerpc_syntax_id *syntax,
680                                            const struct dcerpc_syntax_id *transfer_syntax)
681 {
682         struct composite_context *c;
683         struct ncacn_packet pkt;
684         DATA_BLOB blob;
685         struct rpc_request *req;
686
687         c = composite_create(mem_ctx,p->conn->event_ctx);
688         if (c == NULL) return NULL;
689
690         c->private_data = p;
691
692         p->syntax = *syntax;
693         p->transfer_syntax = *transfer_syntax;
694
695         init_ncacn_hdr(p->conn, &pkt);
696
697         pkt.ptype = DCERPC_PKT_BIND;
698         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
699         pkt.call_id = p->conn->call_id;
700         pkt.auth_length = 0;
701
702         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
703                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
704         }
705
706         pkt.u.bind.max_xmit_frag = 5840;
707         pkt.u.bind.max_recv_frag = 5840;
708         pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
709         pkt.u.bind.num_contexts = 1;
710         pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
711         if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
712         pkt.u.bind.ctx_list[0].context_id = p->context_id;
713         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
714         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
715         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
716         pkt.u.bind.auth_info = data_blob(NULL, 0);
717
718         /* construct the NDR form of the packet */
719         c->status = ncacn_push_auth(&blob, c, &pkt,
720                                     p->conn->security_state.auth_info);
721         if (!composite_is_ok(c)) return c;
722
723         p->conn->transport.recv_data = dcerpc_recv_data;
724
725         /*
726          * we allocate a dcerpc_request so we can be in the same
727          * request queue as normal requests
728          */
729         req = talloc_zero(c, struct rpc_request);
730         if (composite_nomem(req, c)) return c;
731
732         req->state = RPC_REQUEST_PENDING;
733         req->call_id = pkt.call_id;
734         req->async.private = c;
735         req->async.callback = dcerpc_composite_fail;
736         req->p = p;
737         req->recv_handler = dcerpc_bind_recv_handler;
738         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
739         talloc_set_destructor(req, dcerpc_req_dequeue);
740
741         c->status = p->conn->transport.send_request(p->conn, &blob,
742                                                     True);
743         if (!composite_is_ok(c)) return c;
744
745         event_add_timed(c->event_ctx, req,
746                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
747                         dcerpc_timeout_handler, req);
748
749         return c;
750 }
751
752 /*
753   recv side of async dcerpc bind request
754 */
755 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
756 {
757         NTSTATUS result = composite_wait(ctx);
758         talloc_free(ctx);
759         return result;
760 }
761
762 /* 
763    perform a continued bind (and auth3)
764 */
765 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c, 
766                       TALLOC_CTX *mem_ctx)
767 {
768         struct ncacn_packet pkt;
769         NTSTATUS status;
770         DATA_BLOB blob;
771
772         init_ncacn_hdr(c, &pkt);
773
774         pkt.ptype = DCERPC_PKT_AUTH3;
775         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
776         pkt.call_id = next_call_id(c);
777         pkt.auth_length = 0;
778         pkt.u.auth3._pad = 0;
779         pkt.u.auth3.auth_info = data_blob(NULL, 0);
780
781         /* construct the NDR form of the packet */
782         status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
783         if (!NT_STATUS_IS_OK(status)) {
784                 return status;
785         }
786
787         /* send it on its way */
788         status = c->transport.send_request(c, &blob, False);
789         if (!NT_STATUS_IS_OK(status)) {
790                 return status;
791         }
792
793         return status;  
794 }
795
796
797 /*
798   process a fragment received from the transport layer during a
799   request
800
801   This function frees the data 
802 */
803 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
804                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
805 {
806         struct rpc_request *req;
807         uint_t length;
808         NTSTATUS status = NT_STATUS_OK;
809
810         /*
811           if this is an authenticated connection then parse and check
812           the auth info. We have to do this before finding the
813           matching packet, as the request structure might have been
814           removed due to a timeout, but if it has been we still need
815           to run the auth routines so that we don't get the sign/seal
816           info out of step with the server
817         */
818         if (c->security_state.auth_info && c->security_state.generic_state &&
819             pkt->ptype == DCERPC_PKT_RESPONSE) {
820                 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
821         }
822
823         /* find the matching request */
824         for (req=c->pending;req;req=req->next) {
825                 if (pkt->call_id == req->call_id) break;
826         }
827
828 #if 0
829         /* useful for testing certain vendors RPC servers */
830         if (req == NULL && c->pending && pkt->call_id == 0) {
831                 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
832                 req = c->pending;
833         }
834 #endif
835
836         if (req == NULL) {
837                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
838                 data_blob_free(raw_packet);
839                 return;
840         }
841
842         talloc_steal(req, raw_packet->data);
843
844         if (req->recv_handler != NULL) {
845                 dcerpc_req_dequeue(req);
846                 req->state = RPC_REQUEST_DONE;
847                 req->recv_handler(req, raw_packet, pkt);
848                 return;
849         }
850
851         if (pkt->ptype == DCERPC_PKT_FAULT) {
852                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
853                 req->fault_code = pkt->u.fault.status;
854                 req->status = NT_STATUS_NET_WRITE_FAULT;
855                 goto req_done;
856         }
857
858         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
859                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
860                          (int)pkt->ptype)); 
861                 req->fault_code = DCERPC_FAULT_OTHER;
862                 req->status = NT_STATUS_NET_WRITE_FAULT;
863                 goto req_done;
864         }
865
866         /* now check the status from the auth routines, and if it failed then fail
867            this request accordingly */
868         if (!NT_STATUS_IS_OK(status)) {
869                 req->status = status;
870                 goto req_done;
871         }
872
873         length = pkt->u.response.stub_and_verifier.length;
874
875         if (length > 0) {
876                 req->payload.data = talloc_realloc(req, 
877                                                    req->payload.data, 
878                                                    uint8_t,
879                                                    req->payload.length + length);
880                 if (!req->payload.data) {
881                         req->status = NT_STATUS_NO_MEMORY;
882                         goto req_done;
883                 }
884                 memcpy(req->payload.data+req->payload.length, 
885                        pkt->u.response.stub_and_verifier.data, length);
886                 req->payload.length += length;
887         }
888
889         if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
890                 c->transport.send_read(c);
891                 return;
892         }
893
894         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
895                 req->flags |= DCERPC_PULL_BIGENDIAN;
896         } else {
897                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
898         }
899
900
901 req_done:
902         /* we've got the full payload */
903         req->state = RPC_REQUEST_DONE;
904         DLIST_REMOVE(c->pending, req);
905
906         if (c->request_queue != NULL) {
907                 /* We have to look at shipping further requests before calling
908                  * the async function, that one might close the pipe */
909                 dcerpc_ship_next_request(c);
910         }
911
912         if (req->async.callback) {
913                 req->async.callback(req);
914         }
915 }
916
917 /*
918   perform the send side of a async dcerpc request
919 */
920 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
921                                                const struct GUID *object,
922                                                uint16_t opnum,
923                                                BOOL async,
924                                                DATA_BLOB *stub_data)
925 {
926         struct rpc_request *req;
927
928         p->conn->transport.recv_data = dcerpc_recv_data;
929
930         req = talloc(p, struct rpc_request);
931         if (req == NULL) {
932                 return NULL;
933         }
934
935         req->p = p;
936         req->call_id = next_call_id(p->conn);
937         req->status = NT_STATUS_OK;
938         req->state = RPC_REQUEST_QUEUED;
939         req->payload = data_blob(NULL, 0);
940         req->flags = 0;
941         req->fault_code = 0;
942         req->async_call = async;
943         req->async.callback = NULL;
944         req->async.private = NULL;
945         req->recv_handler = NULL;
946
947         if (object != NULL) {
948                 req->object = talloc_memdup(req, object, sizeof(*object));
949                 if (req->object == NULL) {
950                         talloc_free(req);
951                         return NULL;
952                 }
953         } else {
954                 req->object = NULL;
955         }
956
957         req->opnum = opnum;
958         req->request_data.length = stub_data->length;
959         req->request_data.data = talloc_reference(req, stub_data->data);
960         if (req->request_data.length && req->request_data.data == NULL) {
961                 return NULL;
962         }
963
964         DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
965         talloc_set_destructor(req, dcerpc_req_dequeue);
966
967         dcerpc_ship_next_request(p->conn);
968
969         if (p->request_timeout) {
970                 event_add_timed(dcerpc_event_context(p), req, 
971                                 timeval_current_ofs(p->request_timeout, 0), 
972                                 dcerpc_timeout_handler, req);
973         }
974
975         return req;
976 }
977
978 /*
979   Send a request using the transport
980 */
981
982 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
983 {
984         struct rpc_request *req;
985         struct dcerpc_pipe *p;
986         DATA_BLOB *stub_data;
987         struct ncacn_packet pkt;
988         DATA_BLOB blob;
989         uint32_t remaining, chunk_size;
990         BOOL first_packet = True;
991
992         req = c->request_queue;
993         if (req == NULL) {
994                 return;
995         }
996
997         p = req->p;
998         stub_data = &req->request_data;
999
1000         if (!req->async_call && (c->pending != NULL)) {
1001                 return;
1002         }
1003
1004         DLIST_REMOVE(c->request_queue, req);
1005         DLIST_ADD(c->pending, req);
1006         req->state = RPC_REQUEST_PENDING;
1007
1008         init_ncacn_hdr(p->conn, &pkt);
1009
1010         remaining = stub_data->length;
1011
1012         /* we can write a full max_recv_frag size, minus the dcerpc
1013            request header size */
1014         chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1015
1016         pkt.ptype = DCERPC_PKT_REQUEST;
1017         pkt.call_id = req->call_id;
1018         pkt.auth_length = 0;
1019         pkt.pfc_flags = 0;
1020         pkt.u.request.alloc_hint = remaining;
1021         pkt.u.request.context_id = p->context_id;
1022         pkt.u.request.opnum = req->opnum;
1023
1024         if (req->object) {
1025                 pkt.u.request.object.object = *req->object;
1026                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1027                 chunk_size -= ndr_size_GUID(req->object,0);
1028         }
1029
1030         /* we send a series of pdus without waiting for a reply */
1031         while (remaining > 0 || first_packet) {
1032                 uint32_t chunk = MIN(chunk_size, remaining);
1033                 BOOL last_frag = False;
1034
1035                 first_packet = False;
1036                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1037
1038                 if (remaining == stub_data->length) {
1039                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1040                 }
1041                 if (chunk == remaining) {
1042                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1043                         last_frag = True;
1044                 }
1045
1046                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1047                         (stub_data->length - remaining);
1048                 pkt.u.request.stub_and_verifier.length = chunk;
1049
1050                 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1051                 if (!NT_STATUS_IS_OK(req->status)) {
1052                         req->state = RPC_REQUEST_DONE;
1053                         DLIST_REMOVE(p->conn->pending, req);
1054                         return;
1055                 }
1056                 
1057                 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1058                 if (!NT_STATUS_IS_OK(req->status)) {
1059                         req->state = RPC_REQUEST_DONE;
1060                         DLIST_REMOVE(p->conn->pending, req);
1061                         return;
1062                 }               
1063
1064                 remaining -= chunk;
1065         }
1066 }
1067
1068 /*
1069   return the event context for a dcerpc pipe
1070   used by callers who wish to operate asynchronously
1071 */
1072 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1073 {
1074         return p->conn->event_ctx;
1075 }
1076
1077
1078
1079 /*
1080   perform the receive side of a async dcerpc request
1081 */
1082 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1083                              TALLOC_CTX *mem_ctx,
1084                              DATA_BLOB *stub_data)
1085 {
1086         NTSTATUS status;
1087
1088         while (req->state != RPC_REQUEST_DONE) {
1089                 struct event_context *ctx = dcerpc_event_context(req->p);
1090                 if (event_loop_once(ctx) != 0) {
1091                         return NT_STATUS_CONNECTION_DISCONNECTED;
1092                 }
1093         }
1094         *stub_data = req->payload;
1095         status = req->status;
1096         if (stub_data->data) {
1097                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1098         }
1099         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1100                 req->p->last_fault_code = req->fault_code;
1101         }
1102         talloc_free(req);
1103         return status;
1104 }
1105
1106 /*
1107   perform a full request/response pair on a dcerpc pipe
1108 */
1109 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
1110                         struct GUID *object,
1111                         uint16_t opnum,
1112                         BOOL async,
1113                         TALLOC_CTX *mem_ctx,
1114                         DATA_BLOB *stub_data_in,
1115                         DATA_BLOB *stub_data_out)
1116 {
1117         struct rpc_request *req;
1118
1119         req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1120         if (req == NULL) {
1121                 return NT_STATUS_NO_MEMORY;
1122         }
1123
1124         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1125 }
1126
1127
1128 /*
1129   this is a paranoid NDR validator. For every packet we push onto the wire
1130   we pull it back again, then push it again. Then we compare the raw NDR data
1131   for that to the NDR we initially generated. If they don't match then we know
1132   we must have a bug in either the pull or push side of our code
1133 */
1134 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c, 
1135                                        TALLOC_CTX *mem_ctx,
1136                                        DATA_BLOB blob,
1137                                        size_t struct_size,
1138                                        ndr_push_flags_fn_t ndr_push,
1139                                        ndr_pull_flags_fn_t ndr_pull)
1140 {
1141         void *st;
1142         struct ndr_pull *pull;
1143         struct ndr_push *push;
1144         NTSTATUS status;
1145         DATA_BLOB blob2;
1146
1147         st = talloc_size(mem_ctx, struct_size);
1148         if (!st) {
1149                 return NT_STATUS_NO_MEMORY;
1150         }
1151
1152         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1153         if (!pull) {
1154                 return NT_STATUS_NO_MEMORY;
1155         }
1156         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1157
1158         status = ndr_pull(pull, NDR_IN, st);
1159         if (!NT_STATUS_IS_OK(status)) {
1160                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1161                                       "failed input validation pull - %s",
1162                                       nt_errstr(status));
1163         }
1164
1165         push = ndr_push_init_ctx(mem_ctx);
1166         if (!push) {
1167                 return NT_STATUS_NO_MEMORY;
1168         }       
1169
1170         status = ndr_push(push, NDR_IN, st);
1171         if (!NT_STATUS_IS_OK(status)) {
1172                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1173                                       "failed input validation push - %s",
1174                                       nt_errstr(status));
1175         }
1176
1177         blob2 = ndr_push_blob(push);
1178
1179         if (!data_blob_equal(&blob, &blob2)) {
1180                 DEBUG(3,("original:\n"));
1181                 dump_data(3, blob.data, blob.length);
1182                 DEBUG(3,("secondary:\n"));
1183                 dump_data(3, blob2.data, blob2.length);
1184                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1185                                       "failed input validation data - %s",
1186                                       nt_errstr(status));
1187         }
1188
1189         return NT_STATUS_OK;
1190 }
1191
1192 /*
1193   this is a paranoid NDR input validator. For every packet we pull
1194   from the wire we push it back again then pull and push it
1195   again. Then we compare the raw NDR data for that to the NDR we
1196   initially generated. If they don't match then we know we must have a
1197   bug in either the pull or push side of our code
1198 */
1199 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1200                                         struct ndr_pull *pull_in,
1201                                         void *struct_ptr,
1202                                         size_t struct_size,
1203                                         ndr_push_flags_fn_t ndr_push,
1204                                         ndr_pull_flags_fn_t ndr_pull,
1205                                         ndr_print_function_t ndr_print)
1206 {
1207         void *st;
1208         struct ndr_pull *pull;
1209         struct ndr_push *push;
1210         NTSTATUS status;
1211         DATA_BLOB blob, blob2;
1212         TALLOC_CTX *mem_ctx = pull_in;
1213         char *s1, *s2;
1214
1215         st = talloc_size(mem_ctx, struct_size);
1216         if (!st) {
1217                 return NT_STATUS_NO_MEMORY;
1218         }
1219         memcpy(st, struct_ptr, struct_size);
1220
1221         push = ndr_push_init_ctx(mem_ctx);
1222         if (!push) {
1223                 return NT_STATUS_NO_MEMORY;
1224         }       
1225
1226         status = ndr_push(push, NDR_OUT, struct_ptr);
1227         if (!NT_STATUS_IS_OK(status)) {
1228                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1229                                       "failed output validation push - %s",
1230                                       nt_errstr(status));
1231         }
1232
1233         blob = ndr_push_blob(push);
1234
1235         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1236         if (!pull) {
1237                 return NT_STATUS_NO_MEMORY;
1238         }
1239
1240         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1241         status = ndr_pull(pull, NDR_OUT, st);
1242         if (!NT_STATUS_IS_OK(status)) {
1243                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1244                                       "failed output validation pull - %s",
1245                                       nt_errstr(status));
1246         }
1247
1248         push = ndr_push_init_ctx(mem_ctx);
1249         if (!push) {
1250                 return NT_STATUS_NO_MEMORY;
1251         }       
1252
1253         status = ndr_push(push, NDR_OUT, st);
1254         if (!NT_STATUS_IS_OK(status)) {
1255                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1256                                       "failed output validation push2 - %s",
1257                                       nt_errstr(status));
1258         }
1259
1260         blob2 = ndr_push_blob(push);
1261
1262         if (!data_blob_equal(&blob, &blob2)) {
1263                 DEBUG(3,("original:\n"));
1264                 dump_data(3, blob.data, blob.length);
1265                 DEBUG(3,("secondary:\n"));
1266                 dump_data(3, blob2.data, blob2.length);
1267                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1268                                       "failed output validation data - %s",
1269                                       nt_errstr(status));
1270         }
1271
1272         /* this checks the printed forms of the two structures, which effectively
1273            tests all of the value() attributes */
1274         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1275                                        NDR_OUT, struct_ptr);
1276         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1277                                        NDR_OUT, st);
1278         if (strcmp(s1, s2) != 0) {
1279 #if 1
1280                 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1281 #else
1282                 /* this is sometimes useful */
1283                 printf("VALIDATE ERROR\n");
1284                 file_save("wire.dat", s1, strlen(s1));
1285                 file_save("gen.dat", s2, strlen(s2));
1286                 system("diff -u wire.dat gen.dat");
1287 #endif
1288         }
1289
1290         return NT_STATUS_OK;
1291 }
1292
1293
1294 /*
1295  send a rpc request given a dcerpc_call structure 
1296  */
1297 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1298                                                 const struct GUID *object,
1299                                                 const struct dcerpc_interface_table *table,
1300                                                 uint32_t opnum, 
1301                                                 TALLOC_CTX *mem_ctx, 
1302                                                 void *r)
1303 {
1304         const struct dcerpc_interface_call *call;
1305         struct ndr_push *push;
1306         NTSTATUS status;
1307         DATA_BLOB request;
1308         struct rpc_request *req;
1309
1310         call = &table->calls[opnum];
1311
1312         /* setup for a ndr_push_* call */
1313         push = ndr_push_init_ctx(mem_ctx);
1314         if (!push) {
1315                 return NULL;
1316         }
1317
1318         if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1319                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1320         }
1321
1322         /* push the structure into a blob */
1323         status = call->ndr_push(push, NDR_IN, r);
1324         if (!NT_STATUS_IS_OK(status)) {
1325                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1326                          nt_errstr(status)));
1327                 talloc_free(push);
1328                 return NULL;
1329         }
1330
1331         /* retrieve the blob */
1332         request = ndr_push_blob(push);
1333
1334         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1335                 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size, 
1336                                                 call->ndr_push, call->ndr_pull);
1337                 if (!NT_STATUS_IS_OK(status)) {
1338                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1339                                  nt_errstr(status)));
1340                         talloc_free(push);
1341                         return NULL;
1342                 }
1343         }
1344
1345         DEBUG(10,("rpc request data:\n"));
1346         dump_data(10, request.data, request.length);
1347
1348         /* make the actual dcerpc request */
1349         req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1350                                   &request);
1351
1352         if (req != NULL) {
1353                 req->ndr.table = table;
1354                 req->ndr.opnum = opnum;
1355                 req->ndr.struct_ptr = r;
1356                 req->ndr.mem_ctx = mem_ctx;
1357         }
1358
1359         talloc_free(push);
1360
1361         return req;
1362 }
1363
1364 /*
1365   receive the answer from a dcerpc_ndr_request_send()
1366 */
1367 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1368 {
1369         struct dcerpc_pipe *p = req->p;
1370         NTSTATUS status;
1371         DATA_BLOB response;
1372         struct ndr_pull *pull;
1373         uint_t flags;
1374         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1375         void *r = req->ndr.struct_ptr;
1376         uint32_t opnum = req->ndr.opnum;
1377         const struct dcerpc_interface_table *table = req->ndr.table;
1378         const struct dcerpc_interface_call *call = &table->calls[opnum];
1379
1380         /* make sure the recv code doesn't free the request, as we
1381            need to grab the flags element before it is freed */
1382         if (talloc_reference(p, req) == NULL) {
1383                 return NT_STATUS_NO_MEMORY;
1384         }
1385
1386         status = dcerpc_request_recv(req, mem_ctx, &response);
1387         if (!NT_STATUS_IS_OK(status)) {
1388                 talloc_unlink(p, req);
1389                 return status;
1390         }
1391
1392         flags = req->flags;
1393
1394         /* prepare for ndr_pull_* */
1395         pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1396         if (!pull) {
1397                 talloc_unlink(p, req);
1398                 return NT_STATUS_NO_MEMORY;
1399         }
1400
1401         if (pull->data) {
1402                 pull->data = talloc_steal(pull, pull->data);
1403         }
1404         talloc_unlink(p, req);
1405
1406         if (flags & DCERPC_PULL_BIGENDIAN) {
1407                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1408         }
1409
1410         DEBUG(10,("rpc reply data:\n"));
1411         dump_data(10, pull->data, pull->data_size);
1412
1413         /* pull the structure from the blob */
1414         status = call->ndr_pull(pull, NDR_OUT, r);
1415         if (!NT_STATUS_IS_OK(status)) {
1416                 dcerpc_log_packet(table, opnum, NDR_OUT, 
1417                                   &response);
1418                 return status;
1419         }
1420
1421         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1422                 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size, 
1423                                                  call->ndr_push, call->ndr_pull, 
1424                                                  call->ndr_print);
1425                 if (!NT_STATUS_IS_OK(status)) {
1426                         dcerpc_log_packet(table, opnum, NDR_OUT, 
1427                                   &response);
1428                         return status;
1429                 }
1430         }
1431
1432         if (pull->offset != pull->data_size) {
1433                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1434                          pull->data_size - pull->offset));
1435                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1436                    but it turns out that early versions of NT
1437                    (specifically NT3.1) add junk onto the end of rpc
1438                    packets, so if we want to interoperate at all with
1439                    those versions then we need to ignore this error */
1440         }
1441
1442         /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1443
1444         return NT_STATUS_OK;
1445 }
1446
1447
1448 /*
1449   a useful helper function for synchronous rpc requests 
1450
1451   this can be used when you have ndr push/pull functions in the
1452   standard format
1453 */
1454 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1455                             const struct GUID *object,
1456                             const struct dcerpc_interface_table *table,
1457                             uint32_t opnum, 
1458                             TALLOC_CTX *mem_ctx, 
1459                             void *r)
1460 {
1461         struct rpc_request *req;
1462
1463         req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1464         if (req == NULL) {
1465                 return NT_STATUS_NO_MEMORY;
1466         }
1467
1468         return dcerpc_ndr_request_recv(req);
1469 }
1470
1471
1472 /*
1473   a useful function for retrieving the server name we connected to
1474 */
1475 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1476 {
1477         if (!p->conn->transport.peer_name) {
1478                 return "";
1479         }
1480         return p->conn->transport.peer_name(p->conn);
1481 }
1482
1483
1484 /*
1485   get the dcerpc auth_level for a open connection
1486 */
1487 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
1488 {
1489         uint8_t auth_level;
1490
1491         if (c->flags & DCERPC_SEAL) {
1492                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1493         } else if (c->flags & DCERPC_SIGN) {
1494                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1495         } else if (c->flags & DCERPC_CONNECT) {
1496                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1497         } else {
1498                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1499         }
1500         return auth_level;
1501 }
1502
1503 /*
1504   Receive an alter reply from the transport
1505 */
1506 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1507                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1508 {
1509         struct composite_context *c;
1510         struct dcerpc_pipe *recv_pipe;
1511
1512         c = talloc_get_type(req->async.private, struct composite_context);
1513         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1514
1515         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1516             pkt->u.alter_resp.num_results == 1 &&
1517             pkt->u.alter_resp.ctx_list[0].result != 0) {
1518                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1519                          pkt->u.alter_resp.ctx_list[0].reason));
1520                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1521                 return;
1522         }
1523
1524         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1525             pkt->u.alter_resp.num_results == 0 ||
1526             pkt->u.alter_resp.ctx_list[0].result != 0) {
1527                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1528                 return;
1529         }
1530
1531         /* the alter_resp might contain a reply set of credentials */
1532         if (recv_pipe->conn->security_state.auth_info &&
1533             pkt->u.alter_resp.auth_info.length) {
1534                 c->status = ndr_pull_struct_blob(
1535                         &pkt->u.alter_resp.auth_info, recv_pipe,
1536                         recv_pipe->conn->security_state.auth_info,
1537                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1538                 if (!composite_is_ok(c)) return;
1539         }
1540
1541         composite_done(c);
1542 }
1543
1544 /* 
1545    send a dcerpc alter_context request
1546 */
1547 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1548                                                     TALLOC_CTX *mem_ctx,
1549                                                     const struct dcerpc_syntax_id *syntax,
1550                                                     const struct dcerpc_syntax_id *transfer_syntax)
1551 {
1552         struct composite_context *c;
1553         struct ncacn_packet pkt;
1554         DATA_BLOB blob;
1555         struct rpc_request *req;
1556
1557         c = composite_create(mem_ctx, p->conn->event_ctx);
1558         if (c == NULL) return NULL;
1559
1560         c->private_data = p;
1561
1562         p->syntax = *syntax;
1563         p->transfer_syntax = *transfer_syntax;
1564
1565         init_ncacn_hdr(p->conn, &pkt);
1566
1567         pkt.ptype = DCERPC_PKT_ALTER;
1568         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1569         pkt.call_id = p->conn->call_id;
1570         pkt.auth_length = 0;
1571
1572         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1573                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1574         }
1575
1576         pkt.u.alter.max_xmit_frag = 5840;
1577         pkt.u.alter.max_recv_frag = 5840;
1578         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1579         pkt.u.alter.num_contexts = 1;
1580         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1581         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1582         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1583         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1584         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1585         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1586         pkt.u.alter.auth_info = data_blob(NULL, 0);
1587
1588         /* construct the NDR form of the packet */
1589         c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1590                                     p->conn->security_state.auth_info);
1591         if (!composite_is_ok(c)) return c;
1592
1593         p->conn->transport.recv_data = dcerpc_recv_data;
1594
1595         /*
1596          * we allocate a dcerpc_request so we can be in the same
1597          * request queue as normal requests
1598          */
1599         req = talloc_zero(c, struct rpc_request);
1600         if (composite_nomem(req, c)) return c;
1601
1602         req->state = RPC_REQUEST_PENDING;
1603         req->call_id = pkt.call_id;
1604         req->async.private = c;
1605         req->async.callback = dcerpc_composite_fail;
1606         req->p = p;
1607         req->recv_handler = dcerpc_alter_recv_handler;
1608         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1609         talloc_set_destructor(req, dcerpc_req_dequeue);
1610
1611         c->status = p->conn->transport.send_request(p->conn, &blob, True);
1612         if (!composite_is_ok(c)) return c;
1613
1614         event_add_timed(c->event_ctx, req,
1615                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1616                         dcerpc_timeout_handler, req);
1617
1618         return c;
1619 }
1620
1621 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1622 {
1623         NTSTATUS result = composite_wait(ctx);
1624         talloc_free(ctx);
1625         return result;
1626 }
1627
1628 /* 
1629    send a dcerpc alter_context request
1630 */
1631 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
1632                               TALLOC_CTX *mem_ctx,
1633                               const struct dcerpc_syntax_id *syntax,
1634                               const struct dcerpc_syntax_id *transfer_syntax)
1635 {
1636         struct composite_context *creq;
1637         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1638         return dcerpc_alter_context_recv(creq);
1639 }