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