r22944: fix bug #4618:
[tprouty/samba.git] / source4 / librpc / rpc / dcerpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Andrew Tridgell 2003-2005
7    Copyright (C) Jelmer Vernooij 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
32
33 NTSTATUS dcerpc_init(void)
34 {
35         gensec_init();
36
37         return NT_STATUS_OK;
38 }
39
40 static void dcerpc_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_data, 
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_data, 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
677         if (req->ignore_timeout) {
678                 dcerpc_req_dequeue(req);
679                 req->state = RPC_REQUEST_DONE;
680                 req->status = NT_STATUS_IO_TIMEOUT;
681                 if (req->async.callback) {
682                         req->async.callback(req);
683                 }
684                 return;
685         }
686
687         dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
688 }
689
690 /*
691   send a async dcerpc bind request
692 */
693 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
694                                            TALLOC_CTX *mem_ctx,
695                                            const struct dcerpc_syntax_id *syntax,
696                                            const struct dcerpc_syntax_id *transfer_syntax)
697 {
698         struct composite_context *c;
699         struct ncacn_packet pkt;
700         DATA_BLOB blob;
701         struct rpc_request *req;
702
703         c = composite_create(mem_ctx,p->conn->event_ctx);
704         if (c == NULL) return NULL;
705
706         c->private_data = p;
707
708         p->syntax = *syntax;
709         p->transfer_syntax = *transfer_syntax;
710
711         init_ncacn_hdr(p->conn, &pkt);
712
713         pkt.ptype = DCERPC_PKT_BIND;
714         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
715         pkt.call_id = p->conn->call_id;
716         pkt.auth_length = 0;
717
718         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
719                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
720         }
721
722         pkt.u.bind.max_xmit_frag = 5840;
723         pkt.u.bind.max_recv_frag = 5840;
724         pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
725         pkt.u.bind.num_contexts = 1;
726         pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
727         if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
728         pkt.u.bind.ctx_list[0].context_id = p->context_id;
729         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
730         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
731         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
732         pkt.u.bind.auth_info = data_blob(NULL, 0);
733
734         /* construct the NDR form of the packet */
735         c->status = ncacn_push_auth(&blob, c, &pkt,
736                                     p->conn->security_state.auth_info);
737         if (!composite_is_ok(c)) return c;
738
739         p->conn->transport.recv_data = dcerpc_recv_data;
740
741         /*
742          * we allocate a dcerpc_request so we can be in the same
743          * request queue as normal requests
744          */
745         req = talloc_zero(c, struct rpc_request);
746         if (composite_nomem(req, c)) return c;
747
748         req->state = RPC_REQUEST_PENDING;
749         req->call_id = pkt.call_id;
750         req->async.private_data = c;
751         req->async.callback = dcerpc_composite_fail;
752         req->p = p;
753         req->recv_handler = dcerpc_bind_recv_handler;
754         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
755         talloc_set_destructor(req, dcerpc_req_dequeue);
756
757         c->status = p->conn->transport.send_request(p->conn, &blob,
758                                                     True);
759         if (!composite_is_ok(c)) return c;
760
761         event_add_timed(c->event_ctx, req,
762                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
763                         dcerpc_timeout_handler, req);
764
765         return c;
766 }
767
768 /*
769   recv side of async dcerpc bind request
770 */
771 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
772 {
773         NTSTATUS result = composite_wait(ctx);
774         talloc_free(ctx);
775         return result;
776 }
777
778 /* 
779    perform a continued bind (and auth3)
780 */
781 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c, 
782                       TALLOC_CTX *mem_ctx)
783 {
784         struct ncacn_packet pkt;
785         NTSTATUS status;
786         DATA_BLOB blob;
787
788         init_ncacn_hdr(c, &pkt);
789
790         pkt.ptype = DCERPC_PKT_AUTH3;
791         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
792         pkt.call_id = next_call_id(c);
793         pkt.auth_length = 0;
794         pkt.u.auth3._pad = 0;
795         pkt.u.auth3.auth_info = data_blob(NULL, 0);
796
797         /* construct the NDR form of the packet */
798         status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
799         if (!NT_STATUS_IS_OK(status)) {
800                 return status;
801         }
802
803         /* send it on its way */
804         status = c->transport.send_request(c, &blob, False);
805         if (!NT_STATUS_IS_OK(status)) {
806                 return status;
807         }
808
809         return status;  
810 }
811
812
813 /*
814   process a fragment received from the transport layer during a
815   request
816
817   This function frees the data 
818 */
819 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
820                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
821 {
822         struct rpc_request *req;
823         uint_t length;
824         NTSTATUS status = NT_STATUS_OK;
825
826         /*
827           if this is an authenticated connection then parse and check
828           the auth info. We have to do this before finding the
829           matching packet, as the request structure might have been
830           removed due to a timeout, but if it has been we still need
831           to run the auth routines so that we don't get the sign/seal
832           info out of step with the server
833         */
834         if (c->security_state.auth_info && c->security_state.generic_state &&
835             pkt->ptype == DCERPC_PKT_RESPONSE) {
836                 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
837         }
838
839         /* find the matching request */
840         for (req=c->pending;req;req=req->next) {
841                 if (pkt->call_id == req->call_id) break;
842         }
843
844 #if 0
845         /* useful for testing certain vendors RPC servers */
846         if (req == NULL && c->pending && pkt->call_id == 0) {
847                 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
848                 req = c->pending;
849         }
850 #endif
851
852         if (req == NULL) {
853                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
854                 data_blob_free(raw_packet);
855                 return;
856         }
857
858         talloc_steal(req, raw_packet->data);
859
860         if (req->recv_handler != NULL) {
861                 dcerpc_req_dequeue(req);
862                 req->state = RPC_REQUEST_DONE;
863                 req->recv_handler(req, raw_packet, pkt);
864                 return;
865         }
866
867         if (pkt->ptype == DCERPC_PKT_FAULT) {
868                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
869                 req->fault_code = pkt->u.fault.status;
870                 req->status = NT_STATUS_NET_WRITE_FAULT;
871                 goto req_done;
872         }
873
874         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
875                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
876                          (int)pkt->ptype)); 
877                 req->fault_code = DCERPC_FAULT_OTHER;
878                 req->status = NT_STATUS_NET_WRITE_FAULT;
879                 goto req_done;
880         }
881
882         /* now check the status from the auth routines, and if it failed then fail
883            this request accordingly */
884         if (!NT_STATUS_IS_OK(status)) {
885                 req->status = status;
886                 goto req_done;
887         }
888
889         length = pkt->u.response.stub_and_verifier.length;
890
891         if (length > 0) {
892                 req->payload.data = talloc_realloc(req, 
893                                                    req->payload.data, 
894                                                    uint8_t,
895                                                    req->payload.length + length);
896                 if (!req->payload.data) {
897                         req->status = NT_STATUS_NO_MEMORY;
898                         goto req_done;
899                 }
900                 memcpy(req->payload.data+req->payload.length, 
901                        pkt->u.response.stub_and_verifier.data, length);
902                 req->payload.length += length;
903         }
904
905         if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
906                 c->transport.send_read(c);
907                 return;
908         }
909
910         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
911                 req->flags |= DCERPC_PULL_BIGENDIAN;
912         } else {
913                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
914         }
915
916
917 req_done:
918         /* we've got the full payload */
919         req->state = RPC_REQUEST_DONE;
920         DLIST_REMOVE(c->pending, req);
921
922         if (c->request_queue != NULL) {
923                 /* We have to look at shipping further requests before calling
924                  * the async function, that one might close the pipe */
925                 dcerpc_ship_next_request(c);
926         }
927
928         if (req->async.callback) {
929                 req->async.callback(req);
930         }
931 }
932
933 /*
934   perform the send side of a async dcerpc request
935 */
936 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
937                                                const struct GUID *object,
938                                                uint16_t opnum,
939                                                BOOL async,
940                                                DATA_BLOB *stub_data)
941 {
942         struct rpc_request *req;
943
944         p->conn->transport.recv_data = dcerpc_recv_data;
945
946         req = talloc(p, struct rpc_request);
947         if (req == NULL) {
948                 return NULL;
949         }
950
951         req->p = p;
952         req->call_id = next_call_id(p->conn);
953         req->status = NT_STATUS_OK;
954         req->state = RPC_REQUEST_QUEUED;
955         req->payload = data_blob(NULL, 0);
956         req->flags = 0;
957         req->fault_code = 0;
958         req->async_call = async;
959         req->ignore_timeout = False;
960         req->async.callback = NULL;
961         req->async.private_data = NULL;
962         req->recv_handler = NULL;
963
964         if (object != NULL) {
965                 req->object = talloc_memdup(req, object, sizeof(*object));
966                 if (req->object == NULL) {
967                         talloc_free(req);
968                         return NULL;
969                 }
970         } else {
971                 req->object = NULL;
972         }
973
974         req->opnum = opnum;
975         req->request_data.length = stub_data->length;
976         req->request_data.data = talloc_reference(req, stub_data->data);
977         if (req->request_data.length && req->request_data.data == NULL) {
978                 return NULL;
979         }
980
981         DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
982         talloc_set_destructor(req, dcerpc_req_dequeue);
983
984         dcerpc_ship_next_request(p->conn);
985
986         if (p->request_timeout) {
987                 event_add_timed(dcerpc_event_context(p), req, 
988                                 timeval_current_ofs(p->request_timeout, 0), 
989                                 dcerpc_timeout_handler, req);
990         }
991
992         return req;
993 }
994
995 /*
996   Send a request using the transport
997 */
998
999 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1000 {
1001         struct rpc_request *req;
1002         struct dcerpc_pipe *p;
1003         DATA_BLOB *stub_data;
1004         struct ncacn_packet pkt;
1005         DATA_BLOB blob;
1006         uint32_t remaining, chunk_size;
1007         BOOL first_packet = True;
1008
1009         req = c->request_queue;
1010         if (req == NULL) {
1011                 return;
1012         }
1013
1014         p = req->p;
1015         stub_data = &req->request_data;
1016
1017         if (!req->async_call && (c->pending != NULL)) {
1018                 return;
1019         }
1020
1021         DLIST_REMOVE(c->request_queue, req);
1022         DLIST_ADD(c->pending, req);
1023         req->state = RPC_REQUEST_PENDING;
1024
1025         init_ncacn_hdr(p->conn, &pkt);
1026
1027         remaining = stub_data->length;
1028
1029         /* we can write a full max_recv_frag size, minus the dcerpc
1030            request header size */
1031         chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1032
1033         pkt.ptype = DCERPC_PKT_REQUEST;
1034         pkt.call_id = req->call_id;
1035         pkt.auth_length = 0;
1036         pkt.pfc_flags = 0;
1037         pkt.u.request.alloc_hint = remaining;
1038         pkt.u.request.context_id = p->context_id;
1039         pkt.u.request.opnum = req->opnum;
1040
1041         if (req->object) {
1042                 pkt.u.request.object.object = *req->object;
1043                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1044                 chunk_size -= ndr_size_GUID(req->object,0);
1045         }
1046
1047         /* we send a series of pdus without waiting for a reply */
1048         while (remaining > 0 || first_packet) {
1049                 uint32_t chunk = MIN(chunk_size, remaining);
1050                 BOOL last_frag = False;
1051
1052                 first_packet = False;
1053                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1054
1055                 if (remaining == stub_data->length) {
1056                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1057                 }
1058                 if (chunk == remaining) {
1059                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1060                         last_frag = True;
1061                 }
1062
1063                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1064                         (stub_data->length - remaining);
1065                 pkt.u.request.stub_and_verifier.length = chunk;
1066
1067                 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1068                 if (!NT_STATUS_IS_OK(req->status)) {
1069                         req->state = RPC_REQUEST_DONE;
1070                         DLIST_REMOVE(p->conn->pending, req);
1071                         return;
1072                 }
1073                 
1074                 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1075                 if (!NT_STATUS_IS_OK(req->status)) {
1076                         req->state = RPC_REQUEST_DONE;
1077                         DLIST_REMOVE(p->conn->pending, req);
1078                         return;
1079                 }               
1080
1081                 remaining -= chunk;
1082         }
1083 }
1084
1085 /*
1086   return the event context for a dcerpc pipe
1087   used by callers who wish to operate asynchronously
1088 */
1089 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1090 {
1091         return p->conn->event_ctx;
1092 }
1093
1094
1095
1096 /*
1097   perform the receive side of a async dcerpc request
1098 */
1099 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1100                              TALLOC_CTX *mem_ctx,
1101                              DATA_BLOB *stub_data)
1102 {
1103         NTSTATUS status;
1104
1105         while (req->state != RPC_REQUEST_DONE) {
1106                 struct event_context *ctx = dcerpc_event_context(req->p);
1107                 if (event_loop_once(ctx) != 0) {
1108                         return NT_STATUS_CONNECTION_DISCONNECTED;
1109                 }
1110         }
1111         *stub_data = req->payload;
1112         status = req->status;
1113         if (stub_data->data) {
1114                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1115         }
1116         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1117                 req->p->last_fault_code = req->fault_code;
1118         }
1119         talloc_free(req);
1120         return status;
1121 }
1122
1123 /*
1124   perform a full request/response pair on a dcerpc pipe
1125 */
1126 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
1127                         struct GUID *object,
1128                         uint16_t opnum,
1129                         BOOL async,
1130                         TALLOC_CTX *mem_ctx,
1131                         DATA_BLOB *stub_data_in,
1132                         DATA_BLOB *stub_data_out)
1133 {
1134         struct rpc_request *req;
1135
1136         req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1137         if (req == NULL) {
1138                 return NT_STATUS_NO_MEMORY;
1139         }
1140
1141         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1142 }
1143
1144
1145 /*
1146   this is a paranoid NDR validator. For every packet we push onto the wire
1147   we pull it back again, then push it again. Then we compare the raw NDR data
1148   for that to the NDR we initially generated. If they don't match then we know
1149   we must have a bug in either the pull or push side of our code
1150 */
1151 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c, 
1152                                        TALLOC_CTX *mem_ctx,
1153                                        DATA_BLOB blob,
1154                                        size_t struct_size,
1155                                        ndr_push_flags_fn_t ndr_push,
1156                                        ndr_pull_flags_fn_t ndr_pull)
1157 {
1158         void *st;
1159         struct ndr_pull *pull;
1160         struct ndr_push *push;
1161         NTSTATUS status;
1162         DATA_BLOB blob2;
1163
1164         st = talloc_size(mem_ctx, struct_size);
1165         if (!st) {
1166                 return NT_STATUS_NO_MEMORY;
1167         }
1168
1169         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1170         if (!pull) {
1171                 return NT_STATUS_NO_MEMORY;
1172         }
1173         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1174
1175         status = ndr_pull(pull, NDR_IN, st);
1176         if (!NT_STATUS_IS_OK(status)) {
1177                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1178                                       "failed input validation pull - %s",
1179                                       nt_errstr(status));
1180         }
1181
1182         push = ndr_push_init_ctx(mem_ctx);
1183         if (!push) {
1184                 return NT_STATUS_NO_MEMORY;
1185         }       
1186
1187         status = ndr_push(push, NDR_IN, st);
1188         if (!NT_STATUS_IS_OK(status)) {
1189                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1190                                       "failed input validation push - %s",
1191                                       nt_errstr(status));
1192         }
1193
1194         blob2 = ndr_push_blob(push);
1195
1196         if (!data_blob_equal(&blob, &blob2)) {
1197                 DEBUG(3,("original:\n"));
1198                 dump_data(3, blob.data, blob.length);
1199                 DEBUG(3,("secondary:\n"));
1200                 dump_data(3, blob2.data, blob2.length);
1201                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1202                                       "failed input validation data - %s",
1203                                       nt_errstr(status));
1204         }
1205
1206         return NT_STATUS_OK;
1207 }
1208
1209 /*
1210   this is a paranoid NDR input validator. For every packet we pull
1211   from the wire we push it back again then pull and push it
1212   again. Then we compare the raw NDR data for that to the NDR we
1213   initially generated. If they don't match then we know we must have a
1214   bug in either the pull or push side of our code
1215 */
1216 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1217                                         struct ndr_pull *pull_in,
1218                                         void *struct_ptr,
1219                                         size_t struct_size,
1220                                         ndr_push_flags_fn_t ndr_push,
1221                                         ndr_pull_flags_fn_t ndr_pull,
1222                                         ndr_print_function_t ndr_print)
1223 {
1224         void *st;
1225         struct ndr_pull *pull;
1226         struct ndr_push *push;
1227         NTSTATUS status;
1228         DATA_BLOB blob, blob2;
1229         TALLOC_CTX *mem_ctx = pull_in;
1230         char *s1, *s2;
1231
1232         st = talloc_size(mem_ctx, struct_size);
1233         if (!st) {
1234                 return NT_STATUS_NO_MEMORY;
1235         }
1236         memcpy(st, struct_ptr, struct_size);
1237
1238         push = ndr_push_init_ctx(mem_ctx);
1239         if (!push) {
1240                 return NT_STATUS_NO_MEMORY;
1241         }       
1242
1243         status = ndr_push(push, NDR_OUT, struct_ptr);
1244         if (!NT_STATUS_IS_OK(status)) {
1245                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1246                                       "failed output validation push - %s",
1247                                       nt_errstr(status));
1248         }
1249
1250         blob = ndr_push_blob(push);
1251
1252         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1253         if (!pull) {
1254                 return NT_STATUS_NO_MEMORY;
1255         }
1256
1257         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1258         status = ndr_pull(pull, NDR_OUT, st);
1259         if (!NT_STATUS_IS_OK(status)) {
1260                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
1261                                       "failed output validation pull - %s",
1262                                       nt_errstr(status));
1263         }
1264
1265         push = ndr_push_init_ctx(mem_ctx);
1266         if (!push) {
1267                 return NT_STATUS_NO_MEMORY;
1268         }       
1269
1270         status = ndr_push(push, NDR_OUT, st);
1271         if (!NT_STATUS_IS_OK(status)) {
1272                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1273                                       "failed output validation push2 - %s",
1274                                       nt_errstr(status));
1275         }
1276
1277         blob2 = ndr_push_blob(push);
1278
1279         if (!data_blob_equal(&blob, &blob2)) {
1280                 DEBUG(3,("original:\n"));
1281                 dump_data(3, blob.data, blob.length);
1282                 DEBUG(3,("secondary:\n"));
1283                 dump_data(3, blob2.data, blob2.length);
1284                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
1285                                       "failed output validation data - %s",
1286                                       nt_errstr(status));
1287         }
1288
1289         /* this checks the printed forms of the two structures, which effectively
1290            tests all of the value() attributes */
1291         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1292                                        NDR_OUT, struct_ptr);
1293         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1294                                        NDR_OUT, st);
1295         if (strcmp(s1, s2) != 0) {
1296 #if 1
1297                 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1298 #else
1299                 /* this is sometimes useful */
1300                 printf("VALIDATE ERROR\n");
1301                 file_save("wire.dat", s1, strlen(s1));
1302                 file_save("gen.dat", s2, strlen(s2));
1303                 system("diff -u wire.dat gen.dat");
1304 #endif
1305         }
1306
1307         return NT_STATUS_OK;
1308 }
1309
1310
1311 /*
1312  send a rpc request given a dcerpc_call structure 
1313  */
1314 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1315                                                 const struct GUID *object,
1316                                                 const struct dcerpc_interface_table *table,
1317                                                 uint32_t opnum, 
1318                                                 TALLOC_CTX *mem_ctx, 
1319                                                 void *r)
1320 {
1321         const struct dcerpc_interface_call *call;
1322         struct ndr_push *push;
1323         NTSTATUS status;
1324         DATA_BLOB request;
1325         struct rpc_request *req;
1326
1327         call = &table->calls[opnum];
1328
1329         /* setup for a ndr_push_* call */
1330         push = ndr_push_init_ctx(mem_ctx);
1331         if (!push) {
1332                 return NULL;
1333         }
1334
1335         if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1336                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1337         }
1338
1339         /* push the structure into a blob */
1340         status = call->ndr_push(push, NDR_IN, r);
1341         if (!NT_STATUS_IS_OK(status)) {
1342                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1343                          nt_errstr(status)));
1344                 talloc_free(push);
1345                 return NULL;
1346         }
1347
1348         /* retrieve the blob */
1349         request = ndr_push_blob(push);
1350
1351         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1352                 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size, 
1353                                                 call->ndr_push, call->ndr_pull);
1354                 if (!NT_STATUS_IS_OK(status)) {
1355                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1356                                  nt_errstr(status)));
1357                         talloc_free(push);
1358                         return NULL;
1359                 }
1360         }
1361
1362         DEBUG(10,("rpc request data:\n"));
1363         dump_data(10, request.data, request.length);
1364
1365         /* make the actual dcerpc request */
1366         req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1367                                   &request);
1368
1369         if (req != NULL) {
1370                 req->ndr.table = table;
1371                 req->ndr.opnum = opnum;
1372                 req->ndr.struct_ptr = r;
1373                 req->ndr.mem_ctx = mem_ctx;
1374         }
1375
1376         talloc_free(push);
1377
1378         return req;
1379 }
1380
1381 /*
1382   receive the answer from a dcerpc_ndr_request_send()
1383 */
1384 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1385 {
1386         struct dcerpc_pipe *p = req->p;
1387         NTSTATUS status;
1388         DATA_BLOB response;
1389         struct ndr_pull *pull;
1390         uint_t flags;
1391         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1392         void *r = req->ndr.struct_ptr;
1393         uint32_t opnum = req->ndr.opnum;
1394         const struct dcerpc_interface_table *table = req->ndr.table;
1395         const struct dcerpc_interface_call *call = &table->calls[opnum];
1396
1397         /* make sure the recv code doesn't free the request, as we
1398            need to grab the flags element before it is freed */
1399         if (talloc_reference(p, req) == NULL) {
1400                 return NT_STATUS_NO_MEMORY;
1401         }
1402
1403         status = dcerpc_request_recv(req, mem_ctx, &response);
1404         if (!NT_STATUS_IS_OK(status)) {
1405                 talloc_unlink(p, req);
1406                 return status;
1407         }
1408
1409         flags = req->flags;
1410
1411         /* prepare for ndr_pull_* */
1412         pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1413         if (!pull) {
1414                 talloc_unlink(p, req);
1415                 return NT_STATUS_NO_MEMORY;
1416         }
1417
1418         if (pull->data) {
1419                 pull->data = talloc_steal(pull, pull->data);
1420         }
1421         talloc_unlink(p, req);
1422
1423         if (flags & DCERPC_PULL_BIGENDIAN) {
1424                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1425         }
1426
1427         DEBUG(10,("rpc reply data:\n"));
1428         dump_data(10, pull->data, pull->data_size);
1429
1430         /* pull the structure from the blob */
1431         status = call->ndr_pull(pull, NDR_OUT, r);
1432         if (!NT_STATUS_IS_OK(status)) {
1433                 dcerpc_log_packet(table, opnum, NDR_OUT, 
1434                                   &response);
1435                 return status;
1436         }
1437
1438         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1439                 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size, 
1440                                                  call->ndr_push, call->ndr_pull, 
1441                                                  call->ndr_print);
1442                 if (!NT_STATUS_IS_OK(status)) {
1443                         dcerpc_log_packet(table, opnum, NDR_OUT, 
1444                                   &response);
1445                         return status;
1446                 }
1447         }
1448
1449         if (pull->offset != pull->data_size) {
1450                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1451                          pull->data_size - pull->offset));
1452                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1453                    but it turns out that early versions of NT
1454                    (specifically NT3.1) add junk onto the end of rpc
1455                    packets, so if we want to interoperate at all with
1456                    those versions then we need to ignore this error */
1457         }
1458
1459         /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1460
1461         return NT_STATUS_OK;
1462 }
1463
1464
1465 /*
1466   a useful helper function for synchronous rpc requests 
1467
1468   this can be used when you have ndr push/pull functions in the
1469   standard format
1470 */
1471 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1472                             const struct GUID *object,
1473                             const struct dcerpc_interface_table *table,
1474                             uint32_t opnum, 
1475                             TALLOC_CTX *mem_ctx, 
1476                             void *r)
1477 {
1478         struct rpc_request *req;
1479
1480         req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1481         if (req == NULL) {
1482                 return NT_STATUS_NO_MEMORY;
1483         }
1484
1485         return dcerpc_ndr_request_recv(req);
1486 }
1487
1488
1489 /*
1490   a useful function for retrieving the server name we connected to
1491 */
1492 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1493 {
1494         if (!p->conn->transport.peer_name) {
1495                 return "";
1496         }
1497         return p->conn->transport.peer_name(p->conn);
1498 }
1499
1500
1501 /*
1502   get the dcerpc auth_level for a open connection
1503 */
1504 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
1505 {
1506         uint8_t auth_level;
1507
1508         if (c->flags & DCERPC_SEAL) {
1509                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1510         } else if (c->flags & DCERPC_SIGN) {
1511                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1512         } else if (c->flags & DCERPC_CONNECT) {
1513                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1514         } else {
1515                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1516         }
1517         return auth_level;
1518 }
1519
1520 /*
1521   Receive an alter reply from the transport
1522 */
1523 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1524                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1525 {
1526         struct composite_context *c;
1527         struct dcerpc_pipe *recv_pipe;
1528
1529         c = talloc_get_type(req->async.private_data, struct composite_context);
1530         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1531
1532         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1533             pkt->u.alter_resp.num_results == 1 &&
1534             pkt->u.alter_resp.ctx_list[0].result != 0) {
1535                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1536                          pkt->u.alter_resp.ctx_list[0].reason));
1537                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1538                 return;
1539         }
1540
1541         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1542             pkt->u.alter_resp.num_results == 0 ||
1543             pkt->u.alter_resp.ctx_list[0].result != 0) {
1544                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1545                 return;
1546         }
1547
1548         /* the alter_resp might contain a reply set of credentials */
1549         if (recv_pipe->conn->security_state.auth_info &&
1550             pkt->u.alter_resp.auth_info.length) {
1551                 c->status = ndr_pull_struct_blob(
1552                         &pkt->u.alter_resp.auth_info, recv_pipe,
1553                         recv_pipe->conn->security_state.auth_info,
1554                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1555                 if (!composite_is_ok(c)) return;
1556         }
1557
1558         composite_done(c);
1559 }
1560
1561 /* 
1562    send a dcerpc alter_context request
1563 */
1564 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
1565                                                     TALLOC_CTX *mem_ctx,
1566                                                     const struct dcerpc_syntax_id *syntax,
1567                                                     const struct dcerpc_syntax_id *transfer_syntax)
1568 {
1569         struct composite_context *c;
1570         struct ncacn_packet pkt;
1571         DATA_BLOB blob;
1572         struct rpc_request *req;
1573
1574         c = composite_create(mem_ctx, p->conn->event_ctx);
1575         if (c == NULL) return NULL;
1576
1577         c->private_data = p;
1578
1579         p->syntax = *syntax;
1580         p->transfer_syntax = *transfer_syntax;
1581
1582         init_ncacn_hdr(p->conn, &pkt);
1583
1584         pkt.ptype = DCERPC_PKT_ALTER;
1585         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1586         pkt.call_id = p->conn->call_id;
1587         pkt.auth_length = 0;
1588
1589         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1590                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1591         }
1592
1593         pkt.u.alter.max_xmit_frag = 5840;
1594         pkt.u.alter.max_recv_frag = 5840;
1595         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1596         pkt.u.alter.num_contexts = 1;
1597         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1598         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1599         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1600         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1601         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1602         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1603         pkt.u.alter.auth_info = data_blob(NULL, 0);
1604
1605         /* construct the NDR form of the packet */
1606         c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1607                                     p->conn->security_state.auth_info);
1608         if (!composite_is_ok(c)) return c;
1609
1610         p->conn->transport.recv_data = dcerpc_recv_data;
1611
1612         /*
1613          * we allocate a dcerpc_request so we can be in the same
1614          * request queue as normal requests
1615          */
1616         req = talloc_zero(c, struct rpc_request);
1617         if (composite_nomem(req, c)) return c;
1618
1619         req->state = RPC_REQUEST_PENDING;
1620         req->call_id = pkt.call_id;
1621         req->async.private_data = c;
1622         req->async.callback = dcerpc_composite_fail;
1623         req->p = p;
1624         req->recv_handler = dcerpc_alter_recv_handler;
1625         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1626         talloc_set_destructor(req, dcerpc_req_dequeue);
1627
1628         c->status = p->conn->transport.send_request(p->conn, &blob, True);
1629         if (!composite_is_ok(c)) return c;
1630
1631         event_add_timed(c->event_ctx, req,
1632                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1633                         dcerpc_timeout_handler, req);
1634
1635         return c;
1636 }
1637
1638 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1639 {
1640         NTSTATUS result = composite_wait(ctx);
1641         talloc_free(ctx);
1642         return result;
1643 }
1644
1645 /* 
1646    send a dcerpc alter_context request
1647 */
1648 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
1649                               TALLOC_CTX *mem_ctx,
1650                               const struct dcerpc_syntax_id *syntax,
1651                               const struct dcerpc_syntax_id *transfer_syntax)
1652 {
1653         struct composite_context *creq;
1654         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1655         return dcerpc_alter_context_recv(creq);
1656 }