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