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