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