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