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