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