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