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