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