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