STEP01: librpc/rpc/dcerpc_connection.c
[metze/samba/wip.git] / librpc / rpc / dcerpc_connection.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  DCERPC client routines
4  *
5  *  Copyright (C) Stefan Metzmacher 2011
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "system/network.h"
23 #include <tevent.h>
24 #include "lib/util/tevent_ntstatus.h"
25 #include "lib/tsocket/tsocket.h"
26 #include "librpc/gen_ndr/ndr_dcerpc.h"
27 #include "source3/librpc/rpc/dcerpc.h"
28 #include "source4/librpc/rpc/dcerpc.h"
29 #include "auth/gensec/gensec.h"
30 #include "librpc/rpc/dcerpc_connection.h"
31 #include "../lib/util/dlinklist.h"
32
33 struct dcerpc_association;
34 struct dcerpc_connection;
35 struct dcerpc_security;
36 struct dcerpc_presentation;
37 struct dcerpc_call;
38
39 struct dcerpc_association {
40         uint32_t assoc_group_id;
41         uint16_t client_features;
42         uint16_t features;
43         bool negotiate_done;
44         uint32_t next_call_id;
45 };
46
47 struct dcerpc_connection {
48         struct dcerpc_association *assoc;
49
50         struct {
51                 struct tstream_context *stream;
52                 dcerpc_connection_use_trans_fn use_trans_fn;
53                 struct tevent_queue *write_queue;
54         } transport;
55
56         struct {
57                 uint16_t max_xmit_frag;
58                 uint16_t max_recv_frag;
59                 bool concurrent_multiplex;
60                 bool bind_done;
61         } features;
62
63         uint32_t next_sec_context_id;
64         uint16_t next_pres_context_id;
65
66         struct {
67                 struct tevent_queue *out_queue;
68                 struct dcerpc_call *list;
69                 struct dcerpc_call *active;
70                 struct dcerpc_call *new_call;
71         } calls;
72
73         struct {
74                 struct tevent_context *ev;
75                 struct tevent_req *subreq;
76         } loop;
77 };
78
79 struct dcerpc_security {
80         uint32_t context_id;
81         enum dcerpc_AuthType auth_type;
82         enum dcerpc_AuthLevel auth_level;
83         struct gensec_security *gensec;
84 };
85
86 struct dcerpc_presentation {
87         uint16_t context_id;
88         const struct ndr_interface_table *table;
89         struct ndr_syntax_id transfer;
90         struct {
91                 struct dcerpc_ctx_list req;
92                 struct dcerpc_ack_ctx ack;
93         } negotiate;
94 };
95
96 struct dcerpc_call {
97         struct dcerpc_call *prev, *next;
98         uint32_t call_id;
99
100         struct dcerpc_security *sec;
101         struct dcerpc_presentation *pres;
102
103         struct {
104                 void *private_data;
105                 NTSTATUS (*handler)(void *private_data,
106                                     struct ncacn_packet *pkt,
107                                     DATA_BLOB frag);
108         } incoming;
109 };
110
111 struct dcerpc_association *dcerpc_association_create(TALLOC_CTX *mem_ctx,
112                                                      uint16_t client_features)
113 {
114         struct dcerpc_association *assoc;
115
116         assoc = talloc_zero(mem_ctx, struct dcerpc_association);
117         if (assoc == NULL) {
118                 return NULL;
119         }
120
121         assoc->next_call_id = 1;
122
123         assoc->client_features = client_features;
124
125         return assoc;
126 }
127
128 struct dcerpc_connection *dcerpc_connection_create(TALLOC_CTX *mem_ctx,
129                                         struct dcerpc_association *assoc,
130                                         struct tstream_context **stream)
131 {
132         struct dcerpc_connection *conn;
133
134         conn = talloc_zero(mem_ctx, struct dcerpc_connection);
135         if (conn == NULL) {
136                 return NULL;
137         }
138         conn->assoc = assoc;
139
140         conn->transport.stream = talloc_move(conn, stream);
141         conn->transport.write_queue = tevent_queue_create(conn, "write_queue");
142         if (conn->transport.write_queue == NULL) {
143                 talloc_free(conn);
144                 return NULL;
145         }
146
147         conn->features.max_xmit_frag = 4280;
148         conn->features.max_recv_frag = 4280;
149
150         conn->calls.out_queue = tevent_queue_create(conn, "out_queue");
151         if (conn->calls.out_queue == NULL) {
152                 talloc_free(conn);
153                 return NULL;
154         }
155
156         return conn;
157 }
158
159 void dcerpc_connection_set_use_trans_fn(struct dcerpc_connection *conn,
160                                         dcerpc_connection_use_trans_fn fn)
161 {
162         conn->transport.use_trans_fn = fn;
163 }
164
165 struct dcerpc_security *dcerpc_security_allocate(
166                                         TALLOC_CTX *mem_ctx,
167                                         struct dcerpc_connection *conn,
168                                         enum dcerpc_AuthType auth_type,
169                                         enum dcerpc_AuthLevel auth_level,
170                                         struct gensec_security **gensec)
171 {
172         struct dcerpc_security *sec;
173
174         sec = talloc_zero(mem_ctx, struct dcerpc_security);
175         if (sec == NULL) {
176                 return NULL;
177         }
178
179         sec->context_id = conn->next_sec_context_id++;
180         sec->auth_type = auth_type;
181         sec->auth_level = auth_level;
182
183         if (gensec != NULL) {
184                 sec->gensec = talloc_move(sec, gensec);
185         }
186
187         return sec;
188 }
189
190 struct dcerpc_presentation *dcerpc_presentation_allocate(
191                                         TALLOC_CTX *mem_ctx,
192                                         struct dcerpc_connection *conn,
193                                         const struct ndr_interface_table *table,
194                                         const struct ndr_syntax_id *transfer)
195 {
196         struct dcerpc_presentation *pres;
197
198         pres = talloc_zero(mem_ctx, struct dcerpc_presentation);
199         if (pres == NULL) {
200                 return NULL;
201         }
202
203         pres->context_id = conn->next_pres_context_id++;
204         pres->table = table;
205         pres->transfer = *transfer;
206
207         pres->negotiate.req.abstract_syntax = table->syntax_id;
208         pres->negotiate.req.context_id = pres->context_id;
209         pres->negotiate.req.num_transfer_syntaxes = 1;
210         pres->negotiate.req.transfer_syntaxes = &pres->transfer;
211
212         pres->negotiate.ack.result = DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION;
213         pres->negotiate.ack.reason.value =
214                 DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
215
216         return pres;
217 }
218
219 struct dcerpc_call *dcerpc_call_allocate(TALLOC_CTX *mem_ctx,
220                                          struct dcerpc_association *assoc,
221                                          struct dcerpc_security *sec,
222                                          struct dcerpc_presentation *pres)
223 {
224         struct dcerpc_call *call;
225
226         call = talloc_zero(mem_ctx, struct dcerpc_call);
227         if (call == NULL) {
228                 return NULL;
229         }
230
231         call->call_id = assoc->next_call_id++;
232
233         call->sec = sec;
234         call->pres = pres;
235
236         return call;
237 }
238
239 static NTSTATUS dcerpc_guess_pdu_sizes(struct dcerpc_security *sec,
240                                        size_t header_len,
241                                        size_t data_left,
242                                        size_t max_xmit_frag,
243                                        size_t pad_alignment,
244                                        size_t *data_to_send,
245                                        size_t *frag_len,
246                                        size_t *auth_len,
247                                        size_t *pad_len)
248 {
249         size_t max_len;
250         size_t mod_len;
251
252         /* no auth token cases first */
253         switch (sec->auth_level) {
254         case DCERPC_AUTH_LEVEL_NONE:
255         case DCERPC_AUTH_LEVEL_CONNECT:
256         case DCERPC_AUTH_LEVEL_PACKET:
257                 max_len = max_xmit_frag - header_len;
258                 *data_to_send = MIN(max_len, data_left);
259                 *pad_len = 0;
260                 *auth_len = 0;
261                 *frag_len = header_len + *data_to_send;
262                 return NT_STATUS_OK;
263
264         case DCERPC_AUTH_LEVEL_PRIVACY:
265         case DCERPC_AUTH_LEVEL_INTEGRITY:
266                 if (sec->auth_type == DCERPC_AUTH_TYPE_NONE) {
267                         return NT_STATUS_INVALID_PARAMETER_MIX;
268                 }
269                 if (sec->gensec == NULL) {
270                         return NT_STATUS_INVALID_PARAMETER_MIX;
271                 }
272                 break;
273
274         default:
275                 return NT_STATUS_INVALID_PARAMETER;
276         }
277
278
279         /* Sign/seal case, calculate auth and pad lengths */
280
281         max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH;
282
283         *auth_len = gensec_sig_size(sec->gensec, max_len);
284
285         max_len -= *auth_len;
286
287         *data_to_send = MIN(max_len, data_left);
288
289         mod_len = (header_len + *data_to_send) % pad_alignment;
290         if (mod_len) {
291                 *pad_len = pad_alignment - mod_len;
292         } else {
293                 *pad_len = 0;
294         }
295
296         if (*data_to_send + *pad_len > max_len) {
297                 *data_to_send -= pad_alignment;
298         }
299
300         *frag_len = header_len + *data_to_send + *pad_len
301                         + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
302
303         return NT_STATUS_OK;
304 }
305
306 static NTSTATUS dcerpc_ncacn_push_auth(DATA_BLOB *blob,
307                                        TALLOC_CTX *mem_ctx,
308                                        struct ncacn_packet *pkt,
309                                        struct dcerpc_auth *auth_info)
310 {
311         struct ndr_push *ndr;
312         enum ndr_err_code ndr_err;
313
314         ndr = ndr_push_init_ctx(mem_ctx);
315         if (!ndr) {
316                 return NT_STATUS_NO_MEMORY;
317         }
318
319         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
320                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
321         }
322
323         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
324                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
325         }
326
327         if (auth_info) {
328                 pkt->auth_length = auth_info->credentials.length;
329         } else {
330         //      pkt->auth_length = 0;
331         }
332
333         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
334         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
335                 return ndr_map_error2ntstatus(ndr_err);
336         }
337
338         if (auth_info) {
339 #if 0
340                 /* the s3 rpc server doesn't handle auth padding in
341                    bind requests. Use zero auth padding to keep us
342                    working with old servers */
343                 uint32_t offset = ndr->offset;
344                 ndr_err = ndr_push_align(ndr, 16);
345                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
346                         return ndr_map_error2ntstatus(ndr_err);
347                 }
348                 auth_info->auth_pad_length = ndr->offset - offset;
349 #else
350                 auth_info->auth_pad_length = 0;
351 #endif
352                 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
353                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
354                         return ndr_map_error2ntstatus(ndr_err);
355                 }
356         }
357
358         *blob = ndr_push_blob(ndr);
359
360         /* fill in the frag length */
361         dcerpc_set_frag_length(blob, blob->length);
362
363         return NT_STATUS_OK;
364 }
365
366 static NTSTATUS dcerpc_ncacn_packet_blob(TALLOC_CTX *mem_ctx,
367                                          enum dcerpc_pkt_type ptype,
368                                          uint8_t pfc_flags,
369                                          uint16_t auth_length,
370                                          uint32_t call_id,
371                                          union dcerpc_payload *u,
372                                          DATA_BLOB *blob)
373 {
374         struct ncacn_packet r;
375         NTSTATUS status;
376
377         r.rpc_vers              = 5;
378         r.rpc_vers_minor        = 0;
379         r.ptype                 = ptype;
380         r.pfc_flags             = pfc_flags;
381         r.drep[0]               = DCERPC_DREP_LE;
382         r.drep[1]               = 0;
383         r.drep[2]               = 0;
384         r.drep[3]               = 0;
385         r.auth_length           = auth_length;
386         r.call_id               = call_id;
387         r.u                     = *u;
388
389         status = dcerpc_ncacn_push_auth(blob, mem_ctx, &r, NULL);
390         if (!NT_STATUS_IS_OK(status)) {
391                 return status;
392         }
393
394         if (DEBUGLEVEL >= 10) {
395                 /* set frag len for print function */
396                 r.frag_length = blob->length;
397                 NDR_PRINT_DEBUG(ncacn_packet, &r);
398         }
399
400         return NT_STATUS_OK;
401 }
402
403 #define DCERPC_PAYLOAD_PADDING_SIZE 16 //TODO???
404
405 static NTSTATUS dcerpc_auth_blob(TALLOC_CTX *mem_ctx,
406                                  enum dcerpc_AuthType auth_type,
407                                  enum dcerpc_AuthLevel auth_level,
408                                  uint8_t auth_pad_length,
409                                  uint32_t auth_context_id,
410                                  const DATA_BLOB *credentials,
411                                  DATA_BLOB *blob)
412 {
413         struct dcerpc_auth r;
414         enum ndr_err_code ndr_err;
415
416         r.auth_type             = auth_type;
417         r.auth_level            = auth_level;
418         r.auth_pad_length       = auth_pad_length;
419         r.auth_reserved         = 0;
420         r.auth_context_id       = auth_context_id;
421         r.credentials           = *credentials;
422
423         ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
424                 (ndr_push_flags_fn_t)ndr_push_dcerpc_auth);
425         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
426                 return ndr_map_error2ntstatus(ndr_err);
427         }
428
429         if (DEBUGLEVEL >= 10) {
430                 NDR_PRINT_DEBUG(dcerpc_auth, &r);
431         }
432
433         return NT_STATUS_OK;
434 }
435
436 static NTSTATUS dcerpc_response_auth_blob(struct dcerpc_security *sec,
437                                           size_t pad_len,
438                                           DATA_BLOB *rpc_out)
439 {
440         char pad[DCERPC_PAYLOAD_PADDING_SIZE] = { 0, };
441         DATA_BLOB auth_info;
442         DATA_BLOB auth_blob;
443         uint16_t data_and_pad_len = 0;
444         NTSTATUS status;
445
446         if (rpc_out->length < DCERPC_RESPONSE_LENGTH) {
447                 return NT_STATUS_INVALID_PARAMETER_MIX;
448         }
449
450         if (sec->auth_type == DCERPC_AUTH_TYPE_NONE ||
451             sec->auth_type == DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM) {
452                 return NT_STATUS_OK;
453         }
454
455         if (sec->gensec == NULL) {
456                 return NT_STATUS_INVALID_PARAMETER_MIX;
457         }
458
459         if (pad_len) {
460                 /* Copy the sign/seal padding data. */
461                 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
462                         return NT_STATUS_NO_MEMORY;
463                 }
464         }
465
466         data_and_pad_len = rpc_out->length - DCERPC_RESPONSE_LENGTH;
467
468         /* marshall the dcerpc_auth with an actually empty auth_blob.
469          * This is needed because the ntmlssp signature includes the
470          * auth header. We will append the actual blob later. */
471         auth_blob = data_blob_null;
472         status = dcerpc_auth_blob(rpc_out->data,
473                                   sec->auth_type,
474                                   sec->auth_level,
475                                   pad_len,
476                                   sec->context_id,
477                                   &auth_blob,
478                                   &auth_info);
479         if (!NT_STATUS_IS_OK(status)) {
480                 return status;
481         }
482
483         /* append the header */
484         if (!data_blob_append(NULL, rpc_out,
485                                 auth_info.data, auth_info.length)) {
486                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
487                           (unsigned int)auth_info.length));
488                 return NT_STATUS_NO_MEMORY;
489         }
490         data_blob_free(&auth_info);
491
492         switch (sec->auth_level) {
493         case DCERPC_AUTH_LEVEL_PRIVACY:
494                 /* Data portion is encrypted. */
495                 status = gensec_seal_packet(sec->gensec,
496                                             rpc_out->data,
497                                             rpc_out->data
498                                             + DCERPC_RESPONSE_LENGTH,
499                                             data_and_pad_len,
500                                             rpc_out->data,
501                                             rpc_out->length,
502                                             &auth_blob);
503                 if (!NT_STATUS_IS_OK(status)) {
504                         return status;
505                 }
506                 break;
507
508         case DCERPC_AUTH_LEVEL_INTEGRITY:
509                 /* Data is signed. */
510                 status = gensec_sign_packet(sec->gensec,
511                                             rpc_out->data,
512                                             rpc_out->data
513                                             + DCERPC_RESPONSE_LENGTH,
514                                             data_and_pad_len,
515                                             rpc_out->data,
516                                             rpc_out->length,
517                                             &auth_blob);
518                 if (!NT_STATUS_IS_OK(status)) {
519                         return status;
520                 }
521                 break;
522
523         default:
524                 /* Can't happen. */
525                 smb_panic("bad auth level");
526                 /* Notreached. */
527                 return NT_STATUS_INVALID_PARAMETER;
528         }
529
530         /* Finally attach the blob. */
531         if (!data_blob_append(NULL, rpc_out,
532                                 auth_blob.data, auth_blob.length)) {
533                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
534                           (unsigned int)auth_blob.length));
535                 return NT_STATUS_NO_MEMORY;
536         }
537         data_blob_free(&auth_blob);
538
539         return NT_STATUS_OK;
540 }
541
542 static NTSTATUS dcerpc_check_pdu_auth(struct dcerpc_security *sec,
543                            struct ncacn_packet *pkt,
544                            DATA_BLOB *pkt_trailer,
545                            size_t header_size,
546                            DATA_BLOB *raw_pkt,
547                            size_t *pad_len)
548 {
549         NTSTATUS status;
550         struct dcerpc_auth auth_info;
551         uint32_t auth_length;
552         DATA_BLOB full_pkt;
553         DATA_BLOB data;
554
555         switch (sec->auth_level) {
556         case DCERPC_AUTH_LEVEL_PRIVACY:
557                 DEBUG(10, ("Requested Privacy.\n"));
558                 break;
559
560         case DCERPC_AUTH_LEVEL_INTEGRITY:
561                 DEBUG(10, ("Requested Integrity.\n"));
562                 break;
563
564         case DCERPC_AUTH_LEVEL_CONNECT:
565                 if (pkt->auth_length != 0) {
566                         break;
567                 }
568                 *pad_len = 0;
569                 return NT_STATUS_OK;
570
571         case DCERPC_AUTH_LEVEL_NONE:
572                 if (pkt->auth_length != 0) {
573                         DEBUG(3, ("Got non-zero auth len on non "
574                                   "authenticated connection!\n"));
575                         return NT_STATUS_INVALID_PARAMETER;
576                 }
577                 *pad_len = 0;
578                 return NT_STATUS_OK;
579
580         default:
581                 DEBUG(3, ("Unimplemented Auth Level %d",
582                           sec->auth_level));
583                 return NT_STATUS_INVALID_PARAMETER;
584         }
585
586         /* Paranioa checks for auth_length. */
587         if (pkt->auth_length > pkt->frag_length) {
588                 return NT_STATUS_INFO_LENGTH_MISMATCH;
589         }
590         if (((unsigned int)pkt->auth_length
591              + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) ||
592             ((unsigned int)pkt->auth_length
593              + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
594                 /* Integer wrap attempt. */
595                 return NT_STATUS_INFO_LENGTH_MISMATCH;
596         }
597
598         status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
599                                           &auth_info, &auth_length, false);
600         if (!NT_STATUS_IS_OK(status)) {
601                 return status;
602         }
603
604         data = data_blob_const(raw_pkt->data + header_size,
605                                 pkt_trailer->length - auth_length);
606         full_pkt = data_blob_const(raw_pkt->data,
607                                 raw_pkt->length - auth_info.credentials.length);
608
609         switch (sec->auth_type) {
610         case DCERPC_AUTH_TYPE_NONE:
611         case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
612                 return NT_STATUS_OK;
613         default:
614                 break;
615         }
616
617         switch (sec->auth_level) {
618         case DCERPC_AUTH_LEVEL_PRIVACY:
619                 /* Data portion is encrypted. */
620                 status = gensec_unseal_packet(sec->gensec,
621                                             data.data,
622                                             data.length,
623                                             full_pkt.data,
624                                             full_pkt.length,
625                                             &auth_info.credentials);
626                 break;
627
628         case DCERPC_AUTH_LEVEL_INTEGRITY:
629                 /* Data is signed. */
630                 status = gensec_check_packet(sec->gensec,
631                                             data.data,
632                                             data.length,
633                                             full_pkt.data,
634                                             full_pkt.length,
635                                             &auth_info.credentials);
636                 break;
637         default:
638                 return NT_STATUS_INVALID_PARAMETER;
639         }
640         /* TODO: remove later
641          * this is still needed because in the server code the
642          * pkt_trailer actually has a copy of the raw data, and they
643          * are still both used in later calls */
644         if (sec->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
645                 memcpy(pkt_trailer->data, data.data, data.length);
646         }
647
648         *pad_len = auth_info.auth_pad_length;
649         data_blob_free(&auth_info.credentials);
650         return NT_STATUS_OK;
651 }
652
653 static void dcerpc_connection_loop(struct tevent_req *subreq);
654
655 static NTSTATUS dcerpc_connection_loop_restart(struct dcerpc_connection *conn,
656                                                struct tevent_context *ev)
657 {
658         if (ev == NULL) {
659                 return NT_STATUS_INVALID_PARAMETER; // TODO...
660         }
661
662         if (conn->loop.subreq) {
663                 if (conn->loop.ev != ev) {
664                         return NT_STATUS_INVALID_PARAMETER; // TODO...
665                 }
666                 return NT_STATUS_OK;
667         }
668
669         if (conn->calls.list == NULL) {
670                 conn->loop.ev = NULL;
671                 return NT_STATUS_OK;
672         }
673
674         conn->loop.subreq = dcerpc_read_ncacn_packet_send(conn,
675                                                           ev,
676                                                           conn->transport.stream);
677         if (conn->loop.subreq == NULL) {
678                 return NT_STATUS_NO_MEMORY;
679         }
680         tevent_req_set_callback(conn->loop.subreq, dcerpc_connection_loop, conn);
681         conn->loop.ev = ev;
682         return NT_STATUS_OK;
683 }
684
685 static void dcerpc_connection_loop(struct tevent_req *subreq)
686 {
687         struct dcerpc_connection *conn =
688                 tevent_req_callback_data(subreq,
689                 struct dcerpc_connection);
690         NTSTATUS error;
691         struct ncacn_packet *pkt;
692         DATA_BLOB pdu;
693         struct dcerpc_call *call;
694         bool valid_type = false;
695
696         conn->loop.subreq = NULL;
697
698         error = dcerpc_read_ncacn_packet_recv(subreq, subreq, &pkt, &pdu);
699         if (!NT_STATUS_IS_OK(error)) {
700                 TALLOC_FREE(subreq);
701                 // disconnect and notify pending calls
702                 return;
703         }
704
705         if (DEBUGLEVEL >= 10) {
706                 NDR_PRINT_DEBUG(ncacn_packet, pkt);
707         }
708
709         switch (pkt->ptype) {
710         case DCERPC_PKT_REQUEST:
711                 /* Ordinary request. */
712                 valid_type = true;
713                 break;
714
715         case DCERPC_PKT_PING:
716                 /* Connectionless is server alive ? */
717                 break;
718
719         case DCERPC_PKT_RESPONSE:
720                 /* Ordinary reply. */
721                 valid_type = true;
722                 break;
723
724         case DCERPC_PKT_FAULT:
725                 /* Fault in processing of call. */
726                 valid_type = true;
727                 break;
728
729         case DCERPC_PKT_WORKING:
730                 /* Connectionless reply to a ping when server busy. */
731                 break;
732
733         case DCERPC_PKT_NOCALL:
734                 /* Connectionless reply to a ping when server has lost part of clients call. */
735                 break;
736
737         case DCERPC_PKT_REJECT:
738                 /* Refuse a request with a code. */
739                 break;
740
741         case DCERPC_PKT_ACK:
742                 break;
743
744         case DCERPC_PKT_CL_CANCEL:
745                 break;
746
747         case DCERPC_PKT_FACK:
748                 break;
749
750         case DCERPC_PKT_CANCEL_ACK:
751                 /* Server ACK to client cancel request. */
752                 break;
753
754         case DCERPC_PKT_BIND:
755                 /* Bind to interface. */
756                 valid_type = true;
757                 break;
758
759         case DCERPC_PKT_BIND_ACK:
760                 /* Server ack of bind. */
761                 valid_type = true;
762                 break;
763
764         case DCERPC_PKT_BIND_NAK:
765                 /* Server nack of bind. */
766                 valid_type = true;
767                 break;
768
769         case DCERPC_PKT_ALTER:
770                 /* Alter auth. */
771                 valid_type = true;
772                 break;
773
774         case DCERPC_PKT_ALTER_RESP:
775                 /* Reply to alter auth. */
776                 valid_type = true;
777                 break;
778
779         case DCERPC_PKT_AUTH3:
780                 /* not the real name!  this is undocumented! */
781                 valid_type = true;
782                 break;
783
784         case DCERPC_PKT_SHUTDOWN:
785                 /* Server to client request to shutdown. */
786                 valid_type = true;
787                 break;
788
789         case DCERPC_PKT_CO_CANCEL:
790                 /* Connection-oriented cancel request. */
791                 valid_type = true;
792                 break;
793
794         case DCERPC_PKT_ORPHANED:
795                 /* Client telling server it's aborting a partially sent request or telling server to stop sending replies. */
796                 valid_type = true;
797                 break;
798
799         case DCERPC_PKT_RTS:
800                 /* RTS packets used in ncacn_http */
801                 break;
802         }
803
804         if (!valid_type) {
805                 TALLOC_FREE(subreq);
806                 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
807                 return;
808         }
809
810         if (conn->calls.active != NULL) {
811                 if (pkt->call_id != conn->calls.active->call_id) {
812                         TALLOC_FREE(subreq);
813                         // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
814                         return;
815                 }
816                 call = conn->calls.active;
817         } else {
818                 call = conn->calls.list;
819         }
820
821         for (call = conn->calls.list; call; call = call->next) {
822                 if (call->call_id == pkt->call_id) {
823                         break;
824                 }
825         }
826
827         if (call == NULL) {
828                 call = conn->calls.new_call;
829         }
830
831         if (call == NULL) {
832                 TALLOC_FREE(subreq);
833                 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
834                 return;
835         }
836
837         if (call->incoming.handler == NULL) {
838                 TALLOC_FREE(subreq);
839                 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
840                 return;
841         }
842
843         error = call->incoming.handler(call->incoming.private_data, pkt, pdu);
844         TALLOC_FREE(subreq);
845         if (!NT_STATUS_IS_OK(error)) {
846                 // disconnect and notify pending calls
847                 return;
848         }
849
850         if (conn->calls.new_call == NULL) {
851                 conn->loop.ev = NULL;
852                 return;
853         }
854
855         error = dcerpc_connection_loop_restart(conn, conn->loop.ev);
856         if (!NT_STATUS_IS_OK(error)) {
857                 // disconnect and notify pending calls
858                 return;
859         }
860 }
861
862 struct dcerpc_do_bind_out_frag;
863
864 struct dcerpc_do_bind_state {
865         struct tevent_context *ev;
866         struct dcerpc_connection *conn;
867         struct dcerpc_call *call;
868         struct dcerpc_security *sec;
869         DATA_BLOB sec_in;
870         NTSTATUS sec_status;
871         DATA_BLOB sec_out;
872         struct dcerpc_do_bind_out_frag *out_frag;
873         uint32_t num_pres;
874         struct dcerpc_presentation **pres;
875         uint32_t remaining_pres;
876
877         uint32_t num_ctx;
878         struct dcerpc_ctx_list *ctx_list;
879         struct ndr_syntax_id features;
880 };
881
882 struct dcerpc_do_bind_out_frag {
883         struct tevent_context *ev;
884         struct dcerpc_connection *conn;
885         struct tevent_req *req;
886         enum dcerpc_pkt_type ptype;
887         DATA_BLOB blob;
888         struct iovec vector;
889         struct tevent_req *subreq_wait1;
890         struct tevent_req *subreq_wait2;
891 };
892
893 static void dcerpc_do_bind_cleanup(struct tevent_req *req,
894                                    enum tevent_req_state req_state);
895
896 static void dcerpc_do_bind_sec_next(struct tevent_req *subreq);
897 static void dcerpc_do_bind_out_frag_next(struct tevent_req *subreq);
898
899 static NTSTATUS dcerpc_do_bind_handle_in_frag(void *private_data,
900                                               struct ncacn_packet *pkt,
901                                               DATA_BLOB frag);
902
903 struct tevent_req *dcerpc_do_bind_send(TALLOC_CTX *mem_ctx,
904                                 struct tevent_context *ev,
905                                 struct dcerpc_connection *conn,
906                                 struct dcerpc_call *call,
907                                 struct dcerpc_security *sec,
908                                 uint32_t num_pres,
909                                 struct dcerpc_presentation **pres)
910 {
911         struct tevent_req *req;
912         struct dcerpc_do_bind_state *state;
913         struct tevent_req *subreq;
914
915         req = tevent_req_create(mem_ctx, &state,
916                                 struct dcerpc_do_bind_state);
917         if (req == NULL) {
918                 return NULL;
919         }
920         state->ev = ev;
921         state->conn = conn;
922         state->call = call;
923         state->sec = sec;
924         state->num_pres = num_pres;
925         state->pres = pres;
926
927         state->call->incoming.private_data = req;
928         state->call->incoming.handler = dcerpc_do_bind_handle_in_frag;
929         DLIST_ADD_END(state->conn->calls.list, state->call, NULL);
930
931         tevent_req_set_cleanup_fn(req, dcerpc_do_bind_cleanup);
932         tevent_req_defer_callback(req, ev);
933
934         if (state->sec != NULL && state->sec->gensec != NULL) {
935                 subreq = gensec_update_send(state, ev,
936                                             state->sec->gensec,
937                                             state->sec_in);
938                 if (tevent_req_nomem(subreq, req)) {
939                         return tevent_req_post(req, ev);
940                 }
941                 tevent_req_set_callback(subreq, dcerpc_do_bind_sec_next, req);
942
943                 return req;
944         }
945
946         state->sec_status = NT_STATUS_OK;
947
948         subreq = tevent_queue_wait_send(state, state->ev,
949                                         state->conn->calls.out_queue);
950         if (tevent_req_nomem(subreq, req)) {
951                 return tevent_req_post(req, ev);
952         }
953         tevent_req_set_callback(subreq, dcerpc_do_bind_out_frag_next, req);
954
955         return req;
956 }
957
958 static void dcerpc_do_bind_cleanup(struct tevent_req *req,
959                                    enum tevent_req_state req_state)
960 {
961         struct dcerpc_do_bind_state *state =
962                 tevent_req_data(req,
963                 struct dcerpc_do_bind_state);
964
965         if (state->out_frag != NULL) {
966                 state->out_frag->req = NULL;
967                 state->out_frag = NULL;
968         }
969
970         if (state->call != NULL) {
971                 ZERO_STRUCT(state->call->incoming);
972                 DLIST_REMOVE(state->conn->calls.list, state->call);
973                 state->call = NULL;
974         }
975 }
976
977 static void dcerpc_do_bind_sec_next(struct tevent_req *subreq)
978 {
979         struct tevent_req *req =
980                 tevent_req_callback_data(subreq,
981                 struct tevent_req);
982         struct dcerpc_do_bind_state *state =
983                 tevent_req_data(req,
984                 struct dcerpc_do_bind_state);
985         NTSTATUS status;
986
987         data_blob_free(&state->sec_out);
988         status = gensec_update_recv(subreq, state, &state->sec_out);
989         TALLOC_FREE(subreq);
990         data_blob_free(&state->sec_in);
991         state->sec_status = status;
992         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
993                 status = NT_STATUS_OK;
994         }
995         if (!NT_STATUS_IS_OK(status)) {
996                 tevent_req_nterror(req, status);
997                 return;
998         }
999
1000         if (NT_STATUS_IS_OK(state->sec_status) &&
1001             state->sec_out.length == 0)
1002         {
1003                 tevent_req_done(req);
1004                 return;
1005         }
1006
1007         subreq = tevent_queue_wait_send(state, state->ev,
1008                                         state->conn->calls.out_queue);
1009         if (tevent_req_nomem(subreq, req)) {
1010                 return;
1011         }
1012         tevent_req_set_callback(subreq, dcerpc_do_bind_out_frag_next, req);
1013 }
1014
1015 static void dcerpc_do_bind_out_frag_trans_wait1(struct tevent_req *subreq);
1016 static void dcerpc_do_bind_out_frag_done(struct tevent_req *subreq);
1017 static void dcerpc_do_bind_out_frag_trans_wait2(struct tevent_req *subreq);
1018
1019 static void dcerpc_do_bind_out_frag_next(struct tevent_req *subreq)
1020 {
1021         struct tevent_req *req =
1022                 tevent_req_callback_data(subreq,
1023                 struct tevent_req);
1024         struct dcerpc_do_bind_state *state =
1025                 tevent_req_data(req,
1026                 struct dcerpc_do_bind_state);
1027         struct dcerpc_do_bind_out_frag *frag;
1028         size_t auth_len = 0;
1029         NTSTATUS status;
1030         DATA_BLOB auth_info = data_blob_null;
1031         union dcerpc_payload u;
1032         uint32_t i;
1033         bool use_trans = true;
1034         bool ok;
1035
1036         ok = tevent_queue_wait_recv(subreq);
1037         if (!ok) {
1038
1039         }
1040         TALLOC_FREE(subreq);
1041
1042         /*
1043          * the fragment belongs to the connection instead of the request
1044          * because it has to remain in case the request is canceled
1045          */
1046         frag = talloc_zero(state->conn, struct dcerpc_do_bind_out_frag);
1047         if (tevent_req_nomem(frag, req)) {
1048                 return;
1049         }
1050         frag->ev = state->ev;
1051         frag->conn = state->conn;
1052         frag->req = req;
1053         state->out_frag = frag;
1054
1055         if (!state->conn->features.bind_done) {
1056                 frag->ptype = DCERPC_PKT_BIND;
1057         } else if (state->remaining_pres > 0) {
1058                 frag->ptype = DCERPC_PKT_ALTER;
1059         } else if (!NT_STATUS_IS_OK(state->sec_status)) {
1060                 frag->ptype = DCERPC_PKT_ALTER;
1061         } else if (state->sec_out.length > 0) {
1062                 frag->ptype = DCERPC_PKT_AUTH3;
1063         }
1064
1065         if (state->sec) {
1066                 status = dcerpc_auth_blob(frag,
1067                                           state->sec->auth_type,
1068                                           state->sec->auth_level,
1069                                           0, /* auth_pad_length */
1070                                           state->sec->context_id, /* auth_context_id */
1071                                           &state->sec_out,
1072                                           &auth_info);
1073                 if (!NT_STATUS_IS_OK(status)) {
1074                         tevent_req_nterror(req, status);
1075                         return;
1076                 }
1077
1078                 auth_len = auth_info.length;
1079
1080                 if (auth_len) {
1081                         auth_len -= DCERPC_AUTH_TRAILER_LENGTH;
1082                 }
1083         }
1084
1085         state->num_ctx = state->num_pres;
1086         if (!state->conn->assoc->negotiate_done) {
1087                 state->num_ctx += 1;
1088         }
1089
1090         state->ctx_list = talloc_zero_array(frag,
1091                                             struct dcerpc_ctx_list,
1092                                             state->num_ctx);
1093         if (tevent_req_nomem(state->ctx_list, req)) {
1094                 return;
1095         }
1096
1097         for (i=0; i < state->num_pres; i++) {
1098                 state->ctx_list[i] = state->pres[i]->negotiate.req;
1099         }
1100
1101         if (!state->conn->assoc->negotiate_done) {
1102                 state->features = dcerpc_construct_bind_time_features(
1103                                         state->conn->assoc->client_features);
1104
1105                 state->ctx_list[i].context_id = state->conn->next_pres_context_id;
1106                 if (i > 0) {
1107                         state->ctx_list[i].abstract_syntax =
1108                                 state->ctx_list[i-1].abstract_syntax;
1109                 }
1110                 state->ctx_list[i].num_transfer_syntaxes = 1;
1111                 state->ctx_list[i].transfer_syntaxes = &state->features;
1112         }
1113
1114         switch (frag->ptype) {
1115         case DCERPC_PKT_BIND:
1116         case DCERPC_PKT_ALTER:
1117                 u.bind.max_xmit_frag    = state->conn->features.max_xmit_frag;
1118                 u.bind.max_recv_frag    = state->conn->features.max_recv_frag;
1119                 u.bind.assoc_group_id   = state->conn->assoc->assoc_group_id;
1120                 u.bind.num_contexts     = state->num_ctx;
1121                 u.bind.ctx_list         = state->ctx_list;
1122                 u.bind.auth_info        = auth_info;
1123                 break;
1124
1125         case DCERPC_PKT_AUTH3:
1126                 u.auth3._pad            = 0;
1127                 u.auth3.auth_info       = auth_info;
1128                 break;
1129         default:
1130                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1131                 return;
1132         }
1133
1134         status = dcerpc_ncacn_packet_blob(frag,
1135                                           frag->ptype,
1136                                           DCERPC_PFC_FLAG_FIRST |
1137                                           DCERPC_PFC_FLAG_LAST,
1138                                           auth_len,
1139                                           state->call->call_id,
1140                                           &u,
1141                                           &frag->blob);
1142         if (!NT_STATUS_IS_OK(status)) {
1143                 DEBUG(0, ("Failed to marshall bind/alter ncacn_packet.\n"));
1144                 tevent_req_nterror(req, status);
1145                 return;
1146         }
1147
1148         if (frag->ptype == DCERPC_PKT_AUTH3) {
1149                 use_trans = false;
1150         }
1151
1152         if (frag->conn->transport.use_trans_fn == NULL) {
1153                 use_trans = false;
1154         }
1155
1156         if (frag->conn->loop.subreq != NULL) {
1157                 use_trans = false;
1158         }
1159
1160         if (frag->conn->features.concurrent_multiplex) {
1161                 use_trans = false;
1162         }
1163
1164         if (tevent_queue_length(frag->conn->calls.out_queue) > 1) {
1165                 use_trans = false;
1166         }
1167
1168         if (use_trans) {
1169                 frag->subreq_wait1 = tevent_queue_wait_send(frag,
1170                                                 frag->ev,
1171                                                 frag->conn->transport.write_queue);
1172                 if (tevent_req_nomem(req, frag->subreq_wait1)) {
1173                         return;
1174                 }
1175                 tevent_req_set_callback(frag->subreq_wait1,
1176                                         dcerpc_do_bind_out_frag_trans_wait1,
1177                                         frag);
1178                 /*
1179                  * we need to block reads until our write is
1180                  * the next in the write queue.
1181                  */
1182                 frag->conn->loop.subreq = frag->subreq_wait1;
1183                 frag->conn->loop.ev = frag->ev;
1184         }
1185
1186         /*
1187          * We need to add a dcerpc_write_fragment_queue_send/recv()
1188          */
1189
1190         frag->vector.iov_base = frag->blob.data;
1191         frag->vector.iov_len = frag->blob.length;
1192         subreq = tstream_writev_queue_send(frag, frag->ev,
1193                                            frag->conn->transport.stream,
1194                                            frag->conn->transport.write_queue,
1195                                            &frag->vector, 1);
1196         if (tevent_req_nomem(subreq, req)) {
1197                 return;
1198         }
1199         tevent_req_set_callback(subreq,
1200                                 dcerpc_do_bind_out_frag_done,
1201                                 frag);
1202
1203         if (use_trans) {
1204                 frag->subreq_wait2 = tevent_queue_wait_send(frag,
1205                                                 frag->ev,
1206                                                 frag->conn->transport.write_queue);
1207                 if (tevent_req_nomem(req, frag->subreq_wait2)) {
1208                         return;
1209                 }
1210                 tevent_req_set_callback(frag->subreq_wait2,
1211                                         dcerpc_do_bind_out_frag_trans_wait2,
1212                                         frag);
1213         }
1214
1215         status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1216         if (tevent_req_nterror(req, status)) {
1217                 return;
1218         }
1219 }
1220
1221 static void dcerpc_do_bind_out_frag_trans_wait1(struct tevent_req *subreq)
1222 {
1223         struct dcerpc_do_bind_out_frag *frag =
1224                 tevent_req_callback_data(subreq,
1225                 struct dcerpc_do_bind_out_frag);
1226         struct tevent_req *req = frag->req;
1227         NTSTATUS status;
1228         bool ok;
1229
1230         /*
1231          * TODO; what if the caller has been free'ed?
1232          */
1233
1234         frag->subreq_wait1 = NULL;
1235         frag->conn->loop.subreq = NULL;
1236
1237         ok = tevent_queue_wait_recv(subreq);
1238         if (!ok) {
1239                 status = NT_STATUS_INTERNAL_ERROR;
1240                 TALLOC_FREE(frag);
1241                 if (req) {
1242                         tevent_req_nterror(req, status);
1243                 }
1244                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1245                 return;
1246         }
1247
1248         if (tevent_queue_length(frag->conn->transport.write_queue) > 3) {
1249                 /*
1250                  * We added 3 entries into the queue,
1251                  * wait1, writev and wait2.
1252                  *
1253                  * There's more to write, we should not block
1254                  * further writev calls for a trans call.
1255                  *
1256                  * The wait2 stage will trigger the read.
1257                  */
1258                 TALLOC_FREE(subreq);
1259                 return;
1260         }
1261
1262         /*
1263          * we don't need wait2 anymore, we're sure that
1264          * we'll do a trans call.
1265          */
1266         TALLOC_FREE(frag->subreq_wait2);
1267
1268         status = frag->conn->transport.use_trans_fn(frag->conn->transport.stream);
1269         if (!NT_STATUS_IS_OK(status)) {
1270                 TALLOC_FREE(frag);
1271                 if (req) {
1272                         tevent_req_nterror(req, status);
1273                 }
1274                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1275                 return;
1276         }
1277
1278         /* we free subreq after tstream_cli_np_use_trans */
1279         TALLOC_FREE(subreq);
1280
1281         status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1282         if (!NT_STATUS_IS_OK(status)) {
1283                 TALLOC_FREE(frag);
1284                 if (req) {
1285                         tevent_req_nterror(req, status);
1286                 }
1287                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1288                 return;
1289         }
1290 }
1291
1292 static void dcerpc_do_bind_out_frag_done(struct tevent_req *subreq)
1293 {
1294         struct dcerpc_do_bind_out_frag *frag =
1295                 tevent_req_callback_data(subreq,
1296                 struct dcerpc_do_bind_out_frag);
1297         struct tevent_req *req = frag->req;
1298         NTSTATUS status;
1299         int ret;
1300         int sys_errno;
1301
1302         /*
1303          * If the caller has been free'ed, we have should
1304          * ignore any errors and just free 'frag'
1305          */
1306         if (req) {
1307                 struct dcerpc_do_bind_state *state =
1308                         tevent_req_data(req,
1309                         struct dcerpc_do_bind_state);
1310
1311                 state->out_frag = NULL;
1312         }
1313
1314         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1315         TALLOC_FREE(subreq);
1316         if (ret == -1) {
1317                 TALLOC_FREE(frag);
1318                 status = map_nt_error_from_unix_common(sys_errno);
1319                 if (req) {
1320                         tevent_req_nterror(req, status);
1321                 }
1322                 return;
1323         }
1324
1325         if (frag->ptype == DCERPC_PKT_AUTH3) {
1326                 TALLOC_FREE(frag);
1327                 if (req == NULL) {
1328                         return;
1329                 }
1330                 tevent_req_done(req);
1331                 return;
1332         }
1333
1334         if (frag->subreq_wait2 != NULL) {
1335                 return;
1336         }
1337
1338         TALLOC_FREE(frag);
1339
1340         /* we need to wait for incoming pdus */
1341 }
1342
1343 static void dcerpc_do_bind_out_frag_trans_wait2(struct tevent_req *subreq)
1344 {
1345         struct dcerpc_do_bind_out_frag *frag =
1346                 tevent_req_callback_data(subreq,
1347                 struct dcerpc_do_bind_out_frag);
1348         struct tevent_req *req = frag->req;
1349         NTSTATUS status;
1350         bool ok;
1351
1352         frag->subreq_wait2 = NULL;
1353
1354         ok = tevent_queue_wait_recv(subreq);
1355         if (!ok) {
1356                 status = NT_STATUS_INTERNAL_ERROR;
1357                 TALLOC_FREE(frag);
1358                 if (req) {
1359                         tevent_req_nterror(req, status);
1360                 }
1361                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1362                 return;
1363         }
1364
1365         TALLOC_FREE(subreq);
1366
1367         status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1368         if (!NT_STATUS_IS_OK(status)) {
1369                 TALLOC_FREE(frag);
1370                 if (req) {
1371                         tevent_req_nterror(req, status);
1372                 }
1373                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1374                 return;
1375         }
1376
1377         TALLOC_FREE(frag);
1378
1379         /* we need to wait for incoming pdus */
1380 }
1381
1382 static NTSTATUS dcerpc_do_bind_handle_in_frag(void *private_data,
1383                                                  struct ncacn_packet *pkt,
1384                                                  DATA_BLOB frag)
1385 {
1386         struct tevent_req *req =
1387                 talloc_get_type_abort(private_data,
1388                 struct tevent_req);
1389         struct dcerpc_do_bind_state *state =
1390                 tevent_req_data(req,
1391                 struct dcerpc_do_bind_state);
1392         NTSTATUS status;
1393         size_t i;
1394
1395         /* Ensure we have the correct type. */
1396         switch (pkt->ptype) {
1397         case DCERPC_PKT_BIND_ACK:
1398         case DCERPC_PKT_ALTER_RESP:
1399                 if (pkt->auth_length != 0) {
1400                 //      return NT_STATUS_NOT_IMPLEMENTED;
1401                 }
1402
1403                 if (!state->conn->features.bind_done) {
1404                         if (pkt->u.bind_ack.max_recv_frag < 1234) {
1405                                 return NT_STATUS_RPC_PROTOCOL_ERROR;
1406                         }
1407                         if (pkt->u.bind_ack.max_xmit_frag < 1234) {
1408                                 return NT_STATUS_RPC_PROTOCOL_ERROR;
1409                         }
1410                         state->conn->features.max_recv_frag =
1411                                 pkt->u.bind_ack.max_recv_frag;
1412                         state->conn->features.max_xmit_frag =
1413                                 pkt->u.bind_ack.max_xmit_frag;
1414
1415                         if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1416                                 state->conn->features.concurrent_multiplex = true;
1417                         }
1418
1419                         state->conn->features.bind_done = true;
1420                 }
1421
1422                 if (!state->conn->assoc->negotiate_done) {
1423                         state->conn->assoc->negotiate_done = true;
1424                         state->conn->assoc->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1425                 }
1426
1427                 if (pkt->u.bind_ack.assoc_group_id != state->conn->assoc->assoc_group_id) {
1428                         return NT_STATUS_RPC_PROTOCOL_ERROR;
1429                 }
1430
1431                 if (pkt->u.bind_ack.num_results > state->num_ctx) {
1432                         return NT_STATUS_RPC_PROTOCOL_ERROR;
1433                 }
1434
1435                 for (i = 0; i < pkt->u.bind_ack.num_results; i++) {
1436                         struct dcerpc_ack_ctx *ack = &pkt->u.bind_ack.ctx_list[i];
1437
1438                         if (i < state->num_pres) {
1439                                 state->pres[i]->negotiate.ack = *ack;
1440                                 continue;
1441                         }
1442
1443                         if (ack->result != DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1444                                 continue;
1445                         }
1446
1447                         state->conn->assoc->features = state->conn->assoc->client_features;
1448                         state->conn->assoc->features &= ack->reason.negotiate;
1449                 }
1450
1451                 for (i = 0; i < state->num_pres; i++) {
1452                         struct dcerpc_ack_ctx *ack = &state->pres[i]->negotiate.ack;
1453                         bool ok;
1454
1455                         if (ack->result != DCERPC_BIND_ACK_RESULT_ACCEPTANCE) {
1456                                 continue;
1457                         }
1458
1459                         ok = ndr_syntax_id_equal(&state->pres[i]->transfer,
1460                                                  &ack->syntax);
1461                         if (!ok) {
1462                                 return NT_STATUS_RPC_PROTOCOL_ERROR;
1463                         }
1464                 }
1465
1466                 if (pkt->auth_length >= 8) {
1467                         struct tevent_req *subreq;
1468
1469                         state->sec_in = data_blob_talloc(state,
1470                                         pkt->u.bind_ack.auth_info.data + 8,
1471                                         pkt->u.bind_ack.auth_info.length - 8);
1472
1473                         subreq = gensec_update_send(state, state->ev,
1474                                                     state->sec->gensec,
1475                                                     state->sec_in);
1476                         if (tevent_req_nomem(subreq, req)) {
1477                                 return NT_STATUS_OK;
1478                         }
1479                         tevent_req_set_callback(subreq, dcerpc_do_bind_sec_next, req);
1480                         return NT_STATUS_OK;
1481                 }
1482
1483                 tevent_req_done(req);
1484                 return NT_STATUS_OK;
1485
1486         //case DCERPC_PKT_ALTER_RESP:
1487                 if (pkt->auth_length != 0) {
1488                         return NT_STATUS_NOT_IMPLEMENTED;
1489                 }
1490
1491                 return NT_STATUS_NOT_IMPLEMENTED;
1492 //TODO
1493 #if 0
1494                 /* Point the return values at the NDR data. */
1495                 payload.data = frag.data + DCERPC_RESPONSE_LENGTH;
1496
1497                 if (pkt->auth_length) {
1498                         /* We've already done integer wrap tests in
1499                          * dcerpc_check_auth(). */
1500                         payload.length = frag.length
1501                                          - DCERPC_RESPONSE_LENGTH
1502                                          - pad_len
1503                                          - DCERPC_AUTH_TRAILER_LENGTH
1504                                          - pkt->auth_length;
1505                 } else {
1506                         payload.length = frag.length - DCERPC_RESPONSE_LENGTH;
1507                 }
1508
1509                 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1510                         if (pkt->drep[0] & DCERPC_DREP_LE) {
1511                                 state->response.bigendian = false;
1512                         } else {
1513                                 state->response.bigendian = true;
1514                         }
1515                 }
1516
1517                 DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
1518                            (long unsigned int)frag.length,
1519                            (long unsigned int)payload.length,
1520                            (unsigned int)pad_len));
1521
1522                 /*
1523                  * If this is the first reply, and the allocation hint is
1524                  * reasonable, try and set up the reply_pdu DATA_BLOB to the
1525                  * correct size.
1526                  */
1527
1528                 if ((state->response.blob.length == 0) &&
1529                     pkt->u.response.alloc_hint &&
1530                     (pkt->u.response.alloc_hint < 15*1024*1024)) {
1531                         ok = data_blob_realloc(state, &state->response.blob,
1532                                                pkt->u.response.alloc_hint);
1533                         if (!ok) {
1534                                 DEBUG(0, ("reply alloc hint %d too "
1535                                           "large to allocate\n",
1536                                     (int)pkt->u.response.alloc_hint));
1537                                 return NT_STATUS_NO_MEMORY;
1538                         }
1539                 }
1540
1541                 new_total = state->response.ofs + payload.length;
1542
1543                 if (new_total > 15 * 1024 *1024) {
1544                         return NT_STATUS_RPC_PROTOCOL_ERROR;//TODO
1545                 }
1546
1547                 missing = new_total - state->response.blob.length;
1548
1549                 if (missing > 0) {
1550                         ok = data_blob_realloc(state, &state->response.blob,
1551                                                new_total);
1552                         if (!ok) {
1553                                 DEBUG(0, ("reply alloc hint %d too "
1554                                           "large to allocate\n",
1555                                     (int)pkt->u.response.alloc_hint));
1556                                 return NT_STATUS_NO_MEMORY;
1557                         }
1558                 }
1559
1560                 memcpy(state->response.blob.data + state->response.ofs,
1561                        payload.data, payload.length);
1562                 state->response.ofs += payload.length;
1563
1564                 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1565                         tevent_req_done(req);//TODO
1566                         return NT_STATUS_OK;
1567                 }
1568                 return NT_STATUS_OK;
1569 #endif
1570                 return NT_STATUS_NOT_IMPLEMENTED;
1571
1572         case DCERPC_PKT_FAULT:
1573
1574                 DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault "
1575                           "code %s received from %s!\n",
1576                           dcerpc_errstr(talloc_tos(),
1577                           pkt->u.fault.status),
1578                           "TODO"));
1579
1580                 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1581                 if (NT_STATUS_IS_OK(status)) {
1582                         status = NT_STATUS_RPC_PROTOCOL_ERROR;
1583                 }
1584
1585                 tevent_req_nterror(req, status);//TODO
1586                 return NT_STATUS_OK;
1587         default:
1588                 DEBUG(0, ("Unknown packet type %u received from %s!\n",
1589                           (unsigned int)pkt->ptype,
1590                          "TODO"));
1591                 return NT_STATUS_RPC_PROTOCOL_ERROR;
1592         }
1593
1594         return NT_STATUS_RPC_PROTOCOL_ERROR;
1595 }
1596
1597 NTSTATUS dcerpc_do_bind_recv(struct tevent_req *req)
1598 {
1599         struct dcerpc_do_bind_state *state =
1600                 tevent_req_data(req,
1601                 struct dcerpc_do_bind_state);
1602         NTSTATUS status;
1603
1604         if (tevent_req_is_nterror(req, &status)) {
1605                 tevent_req_received(req);
1606                 return status;
1607         }
1608
1609         if (!NT_STATUS_IS_OK(state->sec_status)) {
1610                 status = state->sec_status;
1611                 tevent_req_received(req);
1612                 return status;
1613         }
1614
1615         tevent_req_received(req);
1616         return NT_STATUS_OK;
1617 }
1618
1619 struct dcerpc_do_request_out_frag;
1620
1621 struct dcerpc_do_request_state {
1622         struct tevent_context *ev;
1623         struct dcerpc_connection *conn;
1624         struct dcerpc_call *call;
1625         const struct GUID *object;
1626         uint16_t opnum;
1627         struct {
1628                 const DATA_BLOB *blob;
1629                 size_t ofs;
1630                 bool bigendian;
1631         } request;
1632         struct dcerpc_do_request_out_frag *out_frag;
1633         struct {
1634                 DATA_BLOB blob;
1635                 size_t ofs;
1636                 bool bigendian;
1637         } response;
1638 };
1639
1640 struct dcerpc_do_request_out_frag {
1641         struct tevent_context *ev;
1642         struct dcerpc_connection *conn;
1643         struct tevent_req *req;
1644         DATA_BLOB blob;
1645         bool is_last;
1646         struct iovec vector;
1647         struct tevent_req *subreq_wait1;
1648         struct tevent_req *subreq_wait2;
1649 };
1650
1651 static void dcerpc_do_request_cleanup(struct tevent_req *req,
1652                                       enum tevent_req_state req_state);
1653
1654 static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
1655                                             void *private_data);
1656
1657 static NTSTATUS dcerpc_do_request_handle_in_frag(void *private_data,
1658                                                  struct ncacn_packet *pkt,
1659                                                  DATA_BLOB frag);
1660
1661 struct tevent_req *dcerpc_do_request_send(TALLOC_CTX *mem_ctx,
1662                                 struct tevent_context *ev,
1663                                 struct dcerpc_connection *conn,
1664                                 struct dcerpc_call *call,
1665                                 const struct GUID *object,
1666                                 uint16_t opnum,
1667                                 const DATA_BLOB *request,
1668                                 bool bigendian)
1669 {
1670         struct tevent_req *req;
1671         struct dcerpc_do_request_state *state;
1672         bool ok;
1673
1674         req = tevent_req_create(mem_ctx, &state,
1675                                 struct dcerpc_do_request_state);
1676         if (req == NULL) {
1677                 return NULL;
1678         }
1679         state->ev = ev;
1680         state->conn = conn;
1681         state->call = call;
1682         state->object = object;
1683         state->opnum = opnum;
1684         state->request.blob = request;
1685         state->request.bigendian = bigendian;
1686
1687         state->call->incoming.private_data = req;
1688         state->call->incoming.handler = dcerpc_do_request_handle_in_frag;
1689         DLIST_ADD_END(state->conn->calls.list, state->call, NULL);
1690
1691         tevent_req_set_cleanup_fn(req, dcerpc_do_request_cleanup);
1692         tevent_req_defer_callback(req, ev);
1693
1694         ok = tevent_queue_add(state->conn->calls.out_queue,
1695                               state->ev,
1696                               req,
1697                               dcerpc_do_request_out_frag_next,
1698                               NULL);
1699         if (!ok) {
1700                 tevent_req_nomem(NULL, req);
1701                 return tevent_req_post(req, ev);
1702         }
1703
1704         return req;
1705 }
1706
1707 static void dcerpc_do_request_cleanup(struct tevent_req *req,
1708                                       enum tevent_req_state req_state)
1709 {
1710         struct dcerpc_do_request_state *state =
1711                 tevent_req_data(req,
1712                 struct dcerpc_do_request_state);
1713
1714         if (state->out_frag != NULL) {
1715                 state->out_frag->req = NULL;
1716                 state->out_frag = NULL;
1717         }
1718
1719         if (state->call != NULL) {
1720                 ZERO_STRUCT(state->call->incoming);
1721                 DLIST_REMOVE(state->conn->calls.list, state->call);
1722                 state->call = NULL;
1723         }
1724 }
1725
1726 static void dcerpc_do_request_out_frag_trans_wait1(struct tevent_req *subreq);
1727 static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq);
1728 static void dcerpc_do_request_out_frag_trans_wait2(struct tevent_req *subreq);
1729
1730 static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
1731                                             void *private_data)
1732 {
1733         struct dcerpc_do_request_state *state =
1734                 tevent_req_data(req,
1735                 struct dcerpc_do_request_state);
1736         struct dcerpc_do_request_out_frag *frag;
1737         size_t data_sent_thistime;
1738         size_t hdr_len = DCERPC_REQUEST_LENGTH;
1739         size_t auth_len;
1740         size_t frag_len;
1741         uint8_t flags = 0;
1742         size_t pad_len;
1743         size_t data_left;
1744         NTSTATUS status;
1745         union dcerpc_payload u;
1746         DATA_BLOB payload;
1747         bool ok;
1748         struct tevent_req *subreq;
1749         bool use_trans = true;
1750
1751         if (state->object) {
1752                 flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1753                 hdr_len += 16;
1754         }
1755
1756         /*
1757          * the fragment belongs to the connection instead of the request
1758          * because it has to remain in case the request is canceled
1759          */
1760         frag = talloc_zero(state->conn, struct dcerpc_do_request_out_frag);
1761         if (tevent_req_nomem(frag, req)) {
1762                 return;
1763         }
1764         frag->ev = state->ev;
1765         frag->conn = state->conn;
1766         frag->req = req;
1767         state->out_frag = frag;
1768
1769         data_left = state->request.blob->length - state->request.ofs;
1770
1771         status = dcerpc_guess_pdu_sizes(state->call->sec,
1772                                     hdr_len, data_left,
1773                                     state->conn->features.max_xmit_frag,
1774                                     16,//TODO
1775                                     &data_sent_thistime,
1776                                     &frag_len, &auth_len, &pad_len);
1777         if (!NT_STATUS_IS_OK(status)) {
1778                 tevent_req_nterror(req, status);
1779                 return;
1780         }
1781
1782         if (state->request.ofs == 0) {
1783                 flags |= DCERPC_PFC_FLAG_FIRST;
1784         }
1785
1786         payload.data = state->request.blob->data + state->request.ofs;
1787         payload.length = data_sent_thistime;
1788
1789         state->request.ofs += data_sent_thistime;
1790
1791         if (state->request.blob->length == state->request.ofs) {
1792                 flags |= DCERPC_PFC_FLAG_LAST;
1793         }
1794
1795         ZERO_STRUCT(u.request);
1796
1797         u.request.alloc_hint    = state->request.blob->length -
1798                                   state->request.ofs;
1799         u.request.context_id    = state->call->pres->context_id;
1800         u.request.opnum         = state->opnum;
1801         if (state->object) {
1802                 u.request.object.object = *state->object;
1803         }
1804 //TODO pass state->request.bigendian
1805         status = dcerpc_ncacn_packet_blob(frag,
1806                                           DCERPC_PKT_REQUEST,
1807                                           flags,
1808                                           auth_len,
1809                                           state->call->call_id,
1810                                           &u,
1811                                           &frag->blob);
1812         if (!NT_STATUS_IS_OK(status)) {
1813                 tevent_req_nterror(req, status);
1814                 return;
1815         }
1816
1817         /* explicitly set frag_len here as dcerpc_push_ncacn_packet() can't
1818          * compute it right for requests because the auth trailer is missing
1819          * at this stage */
1820         dcerpc_set_frag_length(&frag->blob, frag_len);
1821
1822         /* Copy in the data. */
1823         ok = data_blob_append(frag, &frag->blob,
1824                               payload.data, payload.length);
1825         if (!ok) {
1826                 tevent_req_nomem(NULL, req);
1827                 return;
1828         }
1829
1830         switch (state->call->sec->auth_level) {
1831         case DCERPC_AUTH_LEVEL_NONE:
1832         case DCERPC_AUTH_LEVEL_CONNECT:
1833         case DCERPC_AUTH_LEVEL_PACKET:
1834                 break;
1835         case DCERPC_AUTH_LEVEL_INTEGRITY:
1836         case DCERPC_AUTH_LEVEL_PRIVACY:
1837                 status = dcerpc_response_auth_blob(state->call->sec,
1838                                                 pad_len,
1839                                                 &frag->blob);
1840                 if (!NT_STATUS_IS_OK(status)) {
1841                         tevent_req_nterror(req, status);
1842                         return;
1843                 }
1844                 break;
1845         default:
1846                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1847                 return;
1848         }
1849
1850         frag->is_last = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
1851
1852         if (!frag->is_last) {
1853                 use_trans = false;
1854         }
1855
1856         if (frag->conn->transport.use_trans_fn == NULL) {
1857                 use_trans = false;
1858         }
1859
1860         if (frag->conn->loop.subreq != NULL) {
1861                 use_trans = false;
1862         }
1863
1864         if (frag->conn->features.concurrent_multiplex) {
1865                 use_trans = false;
1866         }
1867
1868         if (tevent_queue_length(frag->conn->calls.out_queue) > 1) {
1869                 use_trans = false;
1870         }
1871
1872         if (use_trans) {
1873                 frag->subreq_wait1 = tevent_queue_wait_send(frag,
1874                                                 frag->ev,
1875                                                 frag->conn->transport.write_queue);
1876                 if (tevent_req_nomem(req, frag->subreq_wait1)) {
1877                         return;
1878                 }
1879                 tevent_req_set_callback(frag->subreq_wait1,
1880                                         dcerpc_do_request_out_frag_trans_wait1,
1881                                         frag);
1882                 /*
1883                  * we need to block reads until our write is
1884                  * the next in the write queue.
1885                  */
1886                 frag->conn->loop.subreq = frag->subreq_wait1;
1887                 frag->conn->loop.ev = frag->ev;
1888         }
1889
1890         /*
1891          * We need to add a dcerpc_write_fragment_queue_send/recv()
1892          */
1893
1894         frag->vector.iov_base = frag->blob.data;
1895         frag->vector.iov_len = frag->blob.length;
1896         subreq = tstream_writev_queue_send(frag, frag->ev,
1897                                            frag->conn->transport.stream,
1898                                            frag->conn->transport.write_queue,
1899                                            &frag->vector, 1);
1900         if (tevent_req_nomem(subreq, req)) {
1901                 return;
1902         }
1903         tevent_req_set_callback(subreq,
1904                                 dcerpc_do_request_out_frag_done,
1905                                 frag);
1906
1907         if (use_trans) {
1908                 frag->subreq_wait2 = tevent_queue_wait_send(frag,
1909                                                 frag->ev,
1910                                                 frag->conn->transport.write_queue);
1911                 if (tevent_req_nomem(req, frag->subreq_wait2)) {
1912                         return;
1913                 }
1914                 tevent_req_set_callback(frag->subreq_wait2,
1915                                         dcerpc_do_request_out_frag_trans_wait2,
1916                                         frag);
1917         }
1918
1919         if (!frag->is_last) {
1920                 return;
1921         }
1922
1923         status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1924         if (tevent_req_nterror(req, status)) {
1925                 return;
1926         }
1927 }
1928
1929 static void dcerpc_do_request_out_frag_trans_wait1(struct tevent_req *subreq)
1930 {
1931         struct dcerpc_do_request_out_frag *frag =
1932                 tevent_req_callback_data(subreq,
1933                 struct dcerpc_do_request_out_frag);
1934         struct tevent_req *req = frag->req;
1935         NTSTATUS status;
1936         bool ok;
1937
1938         /*
1939          * TODO; what if the caller has been free'ed?
1940          */
1941
1942         frag->subreq_wait1 = NULL;
1943         frag->conn->loop.subreq = NULL;
1944
1945         ok = tevent_queue_wait_recv(subreq);
1946         if (!ok) {
1947                 status = NT_STATUS_INTERNAL_ERROR;
1948                 TALLOC_FREE(frag);
1949                 if (req) {
1950                         tevent_req_nterror(req, status);
1951                 }
1952                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1953                 return;
1954         }
1955
1956         if (tevent_queue_length(frag->conn->transport.write_queue) > 3) {
1957                 /*
1958                  * We added 3 entries into the queue,
1959                  * wait1, writev and wait2.
1960                  *
1961                  * There's more to write, we should not block
1962                  * further writev calls for a trans call.
1963                  *
1964                  * The wait2 stage will trigger the read.
1965                  */
1966                 TALLOC_FREE(subreq);
1967                 return;
1968         }
1969
1970         /*
1971          * we don't need wait2 anymore, we're sure that
1972          * we'll do a trans call.
1973          */
1974         TALLOC_FREE(frag->subreq_wait2);
1975
1976         status = frag->conn->transport.use_trans_fn(frag->conn->transport.stream);
1977         if (!NT_STATUS_IS_OK(status)) {
1978                 TALLOC_FREE(frag);
1979                 if (req) {
1980                         tevent_req_nterror(req, status);
1981                 }
1982                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1983                 return;
1984         }
1985
1986         /* we free subreq after tstream_cli_np_use_trans */
1987         TALLOC_FREE(subreq);
1988
1989         status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1990         if (!NT_STATUS_IS_OK(status)) {
1991                 TALLOC_FREE(frag);
1992                 if (req) {
1993                         tevent_req_nterror(req, status);
1994                 }
1995                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1996                 return;
1997         }
1998 }
1999
2000 static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq)
2001 {
2002         struct dcerpc_do_request_out_frag *frag =
2003                 tevent_req_callback_data(subreq,
2004                 struct dcerpc_do_request_out_frag);
2005         struct tevent_req *req = frag->req;
2006         NTSTATUS status;
2007         int ret;
2008         int sys_errno;
2009
2010         /*
2011          * If the caller has been free'ed, we have should
2012          * ignore any errors and just free 'frag'
2013          */
2014         if (req) {
2015                 struct dcerpc_do_request_state *state =
2016                         tevent_req_data(req,
2017                         struct dcerpc_do_request_state);
2018
2019                 state->out_frag = NULL;
2020         }
2021
2022         ret = tstream_writev_queue_recv(subreq, &sys_errno);
2023         TALLOC_FREE(subreq);
2024         if (ret == -1) {
2025                 TALLOC_FREE(frag);
2026                 status = map_nt_error_from_unix_common(sys_errno);
2027                 if (req) {
2028                         tevent_req_nterror(req, status);
2029                 }
2030                 return;
2031         }
2032
2033         if (frag->subreq_wait2 != NULL) {
2034                 return;
2035         }
2036
2037         if (frag->is_last) {
2038                 TALLOC_FREE(frag);
2039                 return;
2040         }
2041         TALLOC_FREE(frag);
2042
2043         if (req == NULL) {
2044                 return;
2045         }
2046
2047         dcerpc_do_request_out_frag_next(req, NULL);
2048 }
2049
2050 static void dcerpc_do_request_out_frag_trans_wait2(struct tevent_req *subreq)
2051 {
2052         struct dcerpc_do_request_out_frag *frag =
2053                 tevent_req_callback_data(subreq,
2054                 struct dcerpc_do_request_out_frag);
2055         struct tevent_req *req = frag->req;
2056         NTSTATUS status;
2057         bool ok;
2058
2059         frag->subreq_wait2 = NULL;
2060
2061         ok = tevent_queue_wait_recv(subreq);
2062         if (!ok) {
2063                 status = NT_STATUS_INTERNAL_ERROR;
2064                 TALLOC_FREE(frag);
2065                 if (req) {
2066                         tevent_req_nterror(req, status);
2067                 }
2068                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2069                 return;
2070         }
2071
2072         TALLOC_FREE(subreq);
2073
2074         status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
2075         if (!NT_STATUS_IS_OK(status)) {
2076                 TALLOC_FREE(frag);
2077                 if (req) {
2078                         tevent_req_nterror(req, status);
2079                 }
2080                 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2081                 return;
2082         }
2083
2084         TALLOC_FREE(frag);
2085
2086         /* we need to wait for incoming pdus */
2087 }
2088
2089 static NTSTATUS dcerpc_do_request_handle_in_frag(void *private_data,
2090                                                  struct ncacn_packet *pkt,
2091                                                  DATA_BLOB frag)
2092 {
2093         struct tevent_req *req =
2094                 talloc_get_type_abort(private_data,
2095                 struct tevent_req);
2096         struct dcerpc_do_request_state *state =
2097                 tevent_req_data(req,
2098                 struct dcerpc_do_request_state);
2099         NTSTATUS error;
2100         NTSTATUS status;
2101         size_t pad_len = 0;
2102         DATA_BLOB payload;
2103         size_t new_total;
2104         size_t missing;
2105         bool ok;
2106
2107         /* Ensure we have the correct type. */
2108         switch (pkt->ptype) {
2109         case DCERPC_PKT_RESPONSE:
2110
2111                 /* Here's where we deal with incoming sign/seal. */
2112                 error = dcerpc_check_pdu_auth(state->call->sec,
2113                                         pkt,
2114                                         &pkt->u.response.stub_and_verifier,
2115                                         DCERPC_RESPONSE_LENGTH,
2116                                         &frag, &pad_len);
2117                 if (!NT_STATUS_IS_OK(error)) {
2118                         return error;
2119                 }
2120
2121                 if (frag.length < DCERPC_RESPONSE_LENGTH + pad_len) {
2122                         return NT_STATUS_RPC_PROTOCOL_ERROR;
2123                 }
2124 //TODO
2125                 /* Point the return values at the NDR data. */
2126                 payload.data = frag.data + DCERPC_RESPONSE_LENGTH;
2127
2128                 if (pkt->auth_length) {
2129                         /* We've already done integer wrap tests in
2130                          * dcerpc_check_auth(). */
2131                         payload.length = frag.length
2132                                          - DCERPC_RESPONSE_LENGTH
2133                                          - pad_len
2134                                          - DCERPC_AUTH_TRAILER_LENGTH
2135                                          - pkt->auth_length;
2136                 } else {
2137                         payload.length = frag.length - DCERPC_RESPONSE_LENGTH;
2138                 }
2139
2140                 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
2141                         if (pkt->drep[0] & DCERPC_DREP_LE) {
2142                                 state->response.bigendian = false;
2143                         } else {
2144                                 state->response.bigendian = true;
2145                         }
2146                 }
2147
2148                 DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
2149                            (long unsigned int)frag.length,
2150                            (long unsigned int)payload.length,
2151                            (unsigned int)pad_len));
2152
2153                 /*
2154                  * If this is the first reply, and the allocation hint is
2155                  * reasonable, try and set up the reply_pdu DATA_BLOB to the
2156                  * correct size.
2157                  */
2158
2159                 if ((state->response.blob.length == 0) &&
2160                     pkt->u.response.alloc_hint &&
2161                     (pkt->u.response.alloc_hint < 15*1024*1024)) {
2162                         ok = data_blob_realloc(state, &state->response.blob,
2163                                                pkt->u.response.alloc_hint);
2164                         if (!ok) {
2165                                 DEBUG(0, ("reply alloc hint %d too "
2166                                           "large to allocate\n",
2167                                     (int)pkt->u.response.alloc_hint));
2168                                 return NT_STATUS_NO_MEMORY;
2169                         }
2170                 }
2171
2172                 new_total = state->response.ofs + payload.length;
2173
2174                 if (new_total > 15 * 1024 *1024) {
2175                         return NT_STATUS_RPC_PROTOCOL_ERROR;//TODO
2176                 }
2177
2178                 missing = new_total - state->response.blob.length;
2179
2180                 if (missing > 0) {
2181                         ok = data_blob_realloc(state, &state->response.blob,
2182                                                new_total);
2183                         if (!ok) {
2184                                 DEBUG(0, ("reply alloc hint %d too "
2185                                           "large to allocate\n",
2186                                     (int)pkt->u.response.alloc_hint));
2187                                 return NT_STATUS_NO_MEMORY;
2188                         }
2189                 }
2190
2191                 memcpy(state->response.blob.data + state->response.ofs,
2192                        payload.data, payload.length);
2193                 state->response.ofs += payload.length;
2194
2195                 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
2196                         tevent_req_done(req);//TODO
2197                         return NT_STATUS_OK;
2198                 }
2199                 return NT_STATUS_OK;
2200
2201         case DCERPC_PKT_FAULT:
2202
2203                 DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault "
2204                           "code %s received from %s!\n",
2205                           dcerpc_errstr(talloc_tos(),
2206                           pkt->u.fault.status),
2207                           "TODO"));
2208
2209                 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2210                 if (NT_STATUS_IS_OK(status)) {
2211                         status = NT_STATUS_RPC_PROTOCOL_ERROR;
2212                 }
2213
2214                 tevent_req_nterror(req, status);//TODO
2215                 return NT_STATUS_OK;
2216         default:
2217                 DEBUG(0, ("Unknown packet type %u received from %s!\n",
2218                           (unsigned int)pkt->ptype,
2219                          "TODO"));
2220                 return NT_STATUS_RPC_PROTOCOL_ERROR;
2221         }
2222 }
2223
2224 NTSTATUS dcerpc_do_request_recv(struct tevent_req *req,
2225                                 TALLOC_CTX *mem_ctx,
2226                                 DATA_BLOB *response,
2227                                 bool *bigendian)
2228 {
2229         struct dcerpc_do_request_state *state =
2230                 tevent_req_data(req,
2231                 struct dcerpc_do_request_state);
2232         NTSTATUS status;
2233
2234         if (tevent_req_is_nterror(req, &status)) {
2235                 tevent_req_received(req);
2236                 return status;
2237         }
2238
2239         /* return data to caller and assign it ownership of memory */
2240         response->data = talloc_move(mem_ctx, &state->response.blob.data);
2241         response->length = state->response.blob.length;
2242         *bigendian = state->response.bigendian;
2243
2244         tevent_req_received(req);
2245         return NT_STATUS_OK;
2246 }