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