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