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