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