lib: tevent: Use system <tevent.h>, not internal header path (except in self-test).
[samba.git] / source4 / librpc / rpc / dcerpc_roh_channel_out.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    [MS-RPCH] - RPC over HTTP client
5
6    Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
7    Copyright (C) Julien Kerihuel <j.kerihuel@openchange.org> 2013
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include <tevent.h>
25 #include "lib/talloc/talloc.h"
26 #include "lib/tsocket/tsocket.h"
27 #include "lib/tls/tls.h"
28 #include "lib/util/tevent_ntstatus.h"
29 #include "lib/util/util_net.h"
30 #include "libcli/resolve/resolve.h"
31 #include "libcli/composite/composite.h"
32 #include "auth/credentials/credentials.h"
33 #include "auth/credentials/credentials_internal.h"
34 #include <gen_ndr/dcerpc.h>
35 #include <gen_ndr/ndr_dcerpc.h>
36
37 #include "librpc/rpc/dcerpc.h"
38 #include "librpc/rpc/dcerpc_roh.h"
39 #include "librpc/rpc/dcerpc_proto.h"
40 #include "lib/http/http.h"
41
42 struct roh_connect_channel_state {
43         struct tevent_context           *ev;
44         struct tsocket_address          *local_address;
45         struct tsocket_address          *remote_address;
46         struct cli_credentials          *credentials;
47         struct roh_connection           *roh;
48         bool                            tls;
49         struct tstream_tls_params       *tls_params;
50 };
51
52 static void roh_connect_channel_out_done(struct tevent_req *subreq);
53 struct tevent_req *roh_connect_channel_out_send(TALLOC_CTX *mem_ctx,
54                                                 struct tevent_context *ev,
55                                                 const char *rpcproxy_ip_address,
56                                                 unsigned int rpcproxy_port,
57                                                 struct cli_credentials *credentials,
58                                                 struct roh_connection *roh,
59                                                 bool tls,
60                                                 struct tstream_tls_params *tls_params)
61 {
62         NTSTATUS                                status;
63         struct tevent_req                       *req;
64         struct tevent_req                       *subreq;
65         struct roh_connect_channel_state        *state;
66         int                                     ret;
67
68         DEBUG(8, ("%s: Connecting channel out socket, RPC proxy is %s:%d (TLS: %s)\n",
69                   __func__, rpcproxy_ip_address, rpcproxy_port,
70                   (tls ? "true" : "false")));
71
72         req = tevent_req_create(mem_ctx, &state, struct roh_connect_channel_state);
73         if (req == NULL) {
74                 return NULL;
75         }
76
77         if (!is_ipaddress(rpcproxy_ip_address)) {
78                 DEBUG(0, ("%s: Invalid host (%s), needs to be an IP address\n",
79                           __func__, rpcproxy_ip_address));
80                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
81                 return tevent_req_post(req, ev);
82         }
83
84         state->ev = ev;
85         state->credentials = credentials;
86         state->roh = roh;
87         state->tls = tls;
88         state->tls_params = tls_params;
89         ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
90                                                 &state->local_address);
91         if (ret != 0) {
92                 DEBUG(0, ("%s: Cannot create local socket address, error: %s (%d)\n",
93                           __func__, strerror(errno), errno));
94                 status = map_nt_error_from_unix_common(errno);
95                 tevent_req_nterror(req, status);
96                 return tevent_req_post(req, ev);
97         }
98
99         ret = tsocket_address_inet_from_strings(state, "ip",
100                                                 rpcproxy_ip_address,
101                                                 rpcproxy_port,
102                                                 &state->remote_address);
103         if (ret != 0) {
104                 DEBUG(0, ("%s: Cannot create remote socket address, error: %s (%d)\n",
105                           __func__, strerror(errno), errno));
106                 status = map_nt_error_from_unix_common(errno);
107                 tevent_req_nterror(req, status);
108                 return tevent_req_post(req, ev);
109         }
110
111         /* Initialize channel structure */
112         state->roh->default_channel_out = talloc_zero(roh, struct roh_channel);
113         if (tevent_req_nomem(state->roh->default_channel_out, req)) {
114                 return tevent_req_post(req, ev);
115         }
116
117         state->roh->default_channel_out->send_queue =
118                         tevent_queue_create(state->roh->default_channel_out,
119                                             "RoH OUT virtual channel send queue");
120         if (tevent_req_nomem(state->roh->default_channel_out->send_queue, req)) {
121                 return tevent_req_post(req, ev);
122         }
123
124         state->roh->default_channel_out->channel_cookie = GUID_random();
125         subreq = tstream_inet_tcp_connect_send(state, ev, state->local_address,
126                                                state->remote_address);
127         if (tevent_req_nomem(subreq, req)) {
128                 return tevent_req_post(req, ev);
129         }
130         tevent_req_set_callback(subreq, roh_connect_channel_out_done, req);
131
132         return req;
133 }
134
135 static void roh_connect_channel_out_tls_done(struct tevent_req *subreq);
136 static void roh_connect_channel_out_done(struct tevent_req *subreq)
137 {
138         NTSTATUS                                status;
139         struct tevent_req                       *req;
140         struct roh_connect_channel_state        *state;
141         int                                     ret;
142         int                                     sys_errno;
143
144         req = tevent_req_callback_data(subreq, struct tevent_req);
145         state = tevent_req_data(req, struct roh_connect_channel_state);
146         ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno, state,
147                                             &state->roh->default_channel_out->streams.raw,
148                                             NULL);
149         talloc_steal(state->roh->default_channel_out,
150                      state->roh->default_channel_out->streams.raw);
151         state->roh->default_channel_out->streams.active = state->roh->default_channel_out->streams.raw;
152         TALLOC_FREE(subreq);
153         if (ret != 0) {
154                 status = map_nt_error_from_unix_common(sys_errno);
155                 tevent_req_nterror(req, status);
156                 return;
157         }
158
159         DEBUG(8, ("%s: Socket connected\n", __func__));
160         if (state->tls) {
161                 DEBUG(8, ("%s: Starting TLS handshake\n", __func__));
162                 subreq = _tstream_tls_connect_send(state,
163                                                    state->ev,
164                                                    state->roh->default_channel_out->streams.raw,
165                                                    state->tls_params,
166                                                    __location__);
167                 if (tevent_req_nomem(subreq, req)) {
168                         return;
169                 }
170                 tevent_req_set_callback(subreq, roh_connect_channel_out_tls_done, req);
171                 return;
172         }
173
174         tevent_req_done(req);
175 }
176
177 static void roh_connect_channel_out_tls_done(struct tevent_req *subreq)
178 {
179         NTSTATUS                                status;
180         struct tevent_req                       *req;
181         struct roh_connect_channel_state        *state;
182         int                                     ret;
183         int                                     sys_errno;
184
185         req = tevent_req_callback_data(subreq, struct tevent_req);
186         state = tevent_req_data(req, struct roh_connect_channel_state);
187         ret = tstream_tls_connect_recv(subreq, &sys_errno, state,
188                                        &state->roh->default_channel_out->streams.tls);
189         talloc_steal(state->roh->default_channel_out,
190                      state->roh->default_channel_out->streams.tls);
191         state->roh->default_channel_out->streams.active = state->roh->default_channel_out->streams.tls;
192         TALLOC_FREE(subreq);
193         if (ret != 0) {
194                 status = map_nt_error_from_unix_common(sys_errno);
195                 tevent_req_nterror(req, status);
196                 return;
197         }
198         DEBUG(8, ("%s: TLS handshake completed\n", __func__));
199
200         tevent_req_done(req);
201 }
202
203 NTSTATUS roh_connect_channel_out_recv(struct tevent_req *req)
204 {
205         NTSTATUS status;
206
207         if (tevent_req_is_nterror(req, &status)) {
208                 tevent_req_received(req);
209                 return status;
210         }
211
212         tevent_req_received(req);
213         return NT_STATUS_OK;
214 }
215
216 struct roh_request_state {
217         struct http_request     *request;
218         struct http_request     *response;
219 };
220
221 static void roh_send_RPC_DATA_OUT_done(struct tevent_req *subreq);
222 struct tevent_req *roh_send_RPC_DATA_OUT_send(TALLOC_CTX *mem_ctx,
223                                               struct loadparm_context *lp_ctx,
224                                               struct tevent_context *ev,
225                                               struct cli_credentials *credentials,
226                                               struct roh_connection *roh,
227                                               const char *rpc_server,
228                                               uint32_t rpc_server_port,
229                                               const char *rpc_proxy,
230                                               uint8_t http_auth)
231 {
232         struct tevent_req               *req;
233         struct tevent_req               *subreq;
234         struct roh_request_state        *state;
235         const char                      *path;
236         char                            *query;
237         char                            *uri;
238
239         DEBUG(8, ("%s: Sending RPC_OUT_DATA request\n", __func__));
240
241         req = tevent_req_create(mem_ctx, &state, struct roh_request_state);
242         if (req == NULL) {
243                 return NULL;
244         }
245
246         state->request = talloc_zero(state, struct http_request);
247         if (tevent_req_nomem(state->request, req)) {
248                 return tevent_req_post(req, ev);
249         }
250
251         /* Build URI, as specified in section 2.2.2 */
252         query = talloc_asprintf(state, "%s:%d", rpc_server, rpc_server_port);
253         if (tevent_req_nomem(query, req)) {
254                 return tevent_req_post(req, ev);
255         }
256
257         /*
258          * TODO This path changes to "/rpcwithcert/rpcproxy.dll" when using
259          * certificates
260          */
261         path = "/rpc/rpcproxy.dll";
262         uri = talloc_asprintf(state, "%s?%s", path, query);
263         if (tevent_req_nomem(uri, req)) {
264                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
265                 return tevent_req_post(req, ev);
266         }
267         TALLOC_FREE(query);
268
269         /*
270          * Create the HTTP channel OUT request as specified in the
271          * section 2.1.2.1.2
272          */
273         state->request->type = HTTP_REQ_RPC_OUT_DATA;
274         state->request->uri = uri;
275         state->request->body.length = 0;
276         state->request->body.data = NULL;
277         state->request->major = '1';
278         state->request->minor = '0';
279
280         http_add_header(state, &state->request->headers,
281                         "Accept", "application/rpc");
282         http_add_header(state, &state->request->headers,
283                         "User-Agent", "MSRPC");
284         http_add_header(state, &state->request->headers,
285                         "Host", rpc_proxy);
286         http_add_header(state, &state->request->headers,
287                         "Connection", "keep-alive");
288         http_add_header(state, &state->request->headers,
289                         "Content-Length", "76");
290         http_add_header(state, &state->request->headers,
291                         "Cache-Control", "no-cache");
292         http_add_header(state, &state->request->headers,
293                         "Pragma", "no-cache");
294
295         subreq = http_send_auth_request_send(state,
296                                         ev,
297                                         roh->default_channel_out->streams.active,
298                                         roh->default_channel_out->send_queue,
299                                         state->request,
300                                         credentials,
301                                         lp_ctx,
302                                         http_auth);
303         if (tevent_req_nomem(subreq, req)) {
304                 return tevent_req_post(req, ev);
305         }
306         tevent_req_set_callback(subreq, roh_send_RPC_DATA_OUT_done, req);
307
308         return req;
309 }
310
311 static void roh_send_RPC_DATA_OUT_done(struct tevent_req *subreq)
312 {
313         NTSTATUS                status;
314         struct tevent_req       *req;
315
316         req = tevent_req_callback_data(subreq, struct tevent_req);
317
318         /* Receive the sent bytes to check if request has been properly sent */
319         status = http_send_auth_request_recv(subreq);
320         TALLOC_FREE(subreq);
321         if (tevent_req_nterror(req, status)) {
322                 return;
323         }
324
325         DEBUG(8, ("%s: RPC_OUT_DATA sent", __func__));
326
327         tevent_req_done(req);
328 }
329
330 NTSTATUS roh_send_RPC_DATA_OUT_recv(struct tevent_req *req)
331 {
332         NTSTATUS status;
333
334         if (tevent_req_is_nterror(req, &status)) {
335                 tevent_req_received(req);
336                 return status;
337         }
338
339         tevent_req_received(req);
340         return NT_STATUS_OK;
341 }
342
343 struct roh_send_pdu_state {
344         DATA_BLOB       buffer;
345         struct iovec    iov;
346         int             bytes_written;
347         int             sys_errno;
348 };
349
350 static void roh_send_CONN_A1_done(struct tevent_req *subreq);
351 struct tevent_req *roh_send_CONN_A1_send(TALLOC_CTX *mem_ctx,
352                                          struct tevent_context *ev,
353                                          struct roh_connection *roh)
354 {
355         struct tevent_req               *req;
356         struct tevent_req               *subreq;
357         struct roh_send_pdu_state       *state;
358         struct dcerpc_rts               rts;
359         struct ncacn_packet             pkt;
360         struct ndr_push                 *ndr;
361
362         DEBUG(8, ("%s: Sending CONN/A1 request\n", __func__));
363
364         req = tevent_req_create(mem_ctx, &state, struct roh_send_pdu_state);
365         if (req == NULL) {
366                 return NULL;
367         }
368
369         rts.Flags = RTS_FLAG_NONE;
370         rts.NumberOfCommands = 4;
371         rts.Commands = talloc_array(state, struct dcerpc_rts_cmd, 4);
372
373         /* CONN/A1: Version RTS command */
374         rts.Commands[0].CommandType = 0x00000006;
375         rts.Commands[0].Command.Version.Version = 0x00000001;
376
377         /* CONN/A1: VirtualConnectionCookie RTS command */
378         rts.Commands[1].CommandType = 0x00000003;
379         rts.Commands[1].Command.Cookie.Cookie.Cookie = roh->connection_cookie;
380
381         /* CONN/A1: OutChannelCookie RTS command */
382         rts.Commands[2].CommandType = 0x00000003;
383         rts.Commands[2].Command.Cookie.Cookie.Cookie =
384                         roh->default_channel_out->channel_cookie;
385
386         /* CONN/A1: ReceiveWindowSize */
387         rts.Commands[3].CommandType = 0x00000000;
388         rts.Commands[3].Command.ReceiveWindowSize.ReceiveWindowSize = 0x40000;
389
390         pkt.rpc_vers = 5;
391         pkt.rpc_vers_minor = 0;
392         pkt.ptype = DCERPC_PKT_RTS;
393         pkt.pfc_flags = DCERPC_PFC_FLAG_LAST | DCERPC_PFC_FLAG_FIRST;
394         pkt.drep[0] = DCERPC_DREP_LE;
395         pkt.drep[1] = 0;
396         pkt.drep[2] = 0;
397         pkt.drep[3] = 0;
398         pkt.frag_length = 76;
399         pkt.auth_length = 0;
400         pkt.call_id = 0;
401         pkt.u.rts = rts;
402
403         ndr = ndr_push_init_ctx(state);
404         ndr->offset = 0;
405         ndr_push_ncacn_packet(ndr, NDR_SCALARS, &pkt);
406
407         state->buffer = ndr_push_blob(ndr);
408         state->iov.iov_base = (char *) state->buffer.data;
409         state->iov.iov_len = state->buffer.length;
410
411         subreq = tstream_writev_queue_send(mem_ctx,
412                                            ev,
413                                            roh->default_channel_out->streams.active,
414                                            roh->default_channel_out->send_queue,
415                                            &state->iov,
416                                            1);
417         if (tevent_req_nomem(subreq, req)) {
418                 return tevent_req_post(req, ev);
419         }
420         tevent_req_set_callback(subreq, roh_send_CONN_A1_done, req);
421
422         return req;
423 }
424
425 static void roh_send_CONN_A1_done(struct tevent_req *subreq)
426 {
427         NTSTATUS                        status;
428         struct tevent_req               *req;
429         struct roh_send_pdu_state       *state;
430         int                             sys_errno;
431
432         req = tevent_req_callback_data(subreq, struct tevent_req);
433         state = tevent_req_data(req, struct roh_send_pdu_state);
434
435         state->bytes_written = tstream_writev_queue_recv(subreq, &sys_errno);
436         state->sys_errno = sys_errno;
437         TALLOC_FREE(subreq);
438         if (state->bytes_written <= 0 && sys_errno != 0) {
439                 status = map_nt_error_from_unix_common(sys_errno);
440                 tevent_req_nterror(req, status);
441                 return;
442         }
443         DEBUG(8, ("%s: CONN/A1 sent (%d bytes written)\n",
444                   __func__, state->bytes_written));
445
446         tevent_req_done(req);
447 }
448
449 NTSTATUS roh_send_CONN_A1_recv(struct tevent_req *req)
450 {
451         NTSTATUS status;
452
453         if (tevent_req_is_nterror(req, &status)) {
454                 tevent_req_received(req);
455                 return status;
456         }
457
458         tevent_req_received(req);
459         return NT_STATUS_OK;
460 }
461
462 struct roh_recv_response_state
463 {
464         struct http_request     *response;
465 };
466
467 static void roh_recv_out_channel_response_done(struct tevent_req *);
468 struct tevent_req *roh_recv_out_channel_response_send(TALLOC_CTX *mem_ctx,
469                                                       struct tevent_context *ev,
470                                                       struct roh_connection *roh)
471 {
472         struct tevent_req               *req;
473         struct tevent_req               *subreq;
474         struct roh_recv_response_state  *state;
475
476         DEBUG(8, ("%s: Waiting for RPC_OUT_DATA response\n", __func__));
477
478         req = tevent_req_create(mem_ctx, &state, struct roh_recv_response_state);
479         if (req == NULL) {
480                 return NULL;
481         }
482
483         subreq = http_read_response_send(state, ev,
484                                          roh->default_channel_out->streams.active,
485                                          0); /* we'll get the content later */
486         if (tevent_req_nomem(subreq, req)) {
487                 return tevent_req_post(req, ev);
488         }
489         tevent_req_set_callback(subreq, roh_recv_out_channel_response_done, req);
490
491         return req;
492 }
493
494 static void roh_recv_out_channel_response_done(struct tevent_req *subreq)
495 {
496         NTSTATUS                        status;
497         struct tevent_req               *req;
498         struct roh_recv_response_state  *state;
499
500         req = tevent_req_callback_data(subreq, struct tevent_req);
501         state = tevent_req_data(req, struct roh_recv_response_state);
502         status = http_read_response_recv(subreq, state, &state->response);
503         TALLOC_FREE(subreq);
504         if (tevent_req_nterror(req, status)) {
505                 return;
506         }
507
508         DEBUG(8, ("%s: RCP_OUT_DATA response received\n", __func__));
509
510         /* TODO Map response code to nt error */
511         switch (state->response->response_code) {
512         case 200:
513                 break;
514         case 401:
515                 DEBUG(0, ("%s: Server response: Access denied\n", __func__));
516                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
517                 return;
518         case 503:
519                 /* TODO Decode error info as specified in section 2.1.2.1.3 */
520                 DEBUG(0, ("%s: Server response: RPC error\n", __func__));
521                 tevent_req_nterror(req, NT_STATUS_GENERIC_NOT_MAPPED);
522                 return;
523         default:
524                 DEBUG(0, ("%s: Server response: Unknown error\n", __func__));
525                 tevent_req_nterror(req, NT_STATUS_GENERIC_NOT_MAPPED);
526                 return;
527         }
528
529         tevent_req_done(req);
530 }
531
532 NTSTATUS roh_recv_out_channel_response_recv(struct tevent_req *req,
533                 TALLOC_CTX *mem_ctx,
534                 char **response_msg)
535 {
536         NTSTATUS status;
537
538         if (tevent_req_is_nterror(req, &status)) {
539                 tevent_req_received(req);
540                 return status;
541         }
542
543         tevent_req_received(req);
544         return NT_STATUS_OK;
545 }
546
547 struct roh_recv_pdu_state {
548         struct roh_connection   *roh;
549         uint32_t                connection_timeout;
550         uint32_t                version;
551         uint32_t                recv_window_size;
552 };
553
554 static void roh_recv_CONN_A3_done(struct tevent_req *subreq);
555 struct tevent_req *roh_recv_CONN_A3_send(TALLOC_CTX *mem_ctx,
556                                          struct tevent_context *ev,
557                                          struct roh_connection *roh)
558 {
559         struct tevent_req               *req;
560         struct tevent_req               *subreq;
561         struct roh_recv_pdu_state       *state;
562
563         req = tevent_req_create(mem_ctx, &state, struct roh_recv_pdu_state);
564         if (req == NULL) {
565                 return NULL;
566         }
567
568         DEBUG(8, ("%s: Waiting for CONN/A3\n", __func__));
569         subreq = dcerpc_read_ncacn_packet_send(state, ev,
570                                                roh->default_channel_out->streams.active);
571         if (tevent_req_nomem(subreq, req)) {
572                 return tevent_req_post(req, ev);
573         }
574         tevent_req_set_callback(subreq, roh_recv_CONN_A3_done, req);
575
576         return req;
577 }
578
579 static void roh_recv_CONN_A3_done(struct tevent_req *subreq)
580 {
581         NTSTATUS                        status;
582         struct tevent_req               *req;
583         struct roh_recv_pdu_state       *state;
584         struct ncacn_packet             *pkt;
585         DATA_BLOB                       buffer;
586         struct dcerpc_rts               rts;
587
588         req = tevent_req_callback_data(subreq, struct tevent_req);
589         state = tevent_req_data(req, struct roh_recv_pdu_state);
590         status = dcerpc_read_ncacn_packet_recv(subreq, state, &pkt, &buffer);
591         TALLOC_FREE(subreq);
592
593         if (tevent_req_nterror(req, status)) {
594                 DEBUG(0, ("%s: Error receiving PDU\n", __func__));
595                 return;
596         }
597
598         /*
599          * Check if it is a CONN/A3 (2.2.4.4) packet and get the connection
600          * timeout
601          */
602         rts = pkt->u.rts;
603         if (rts.NumberOfCommands != 1) {
604                 DEBUG(0, ("%s: Invalid number of commands received\n", __func__));
605                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
606                 return;
607         }
608
609         if (rts.Commands[0].CommandType != ROH_CMD_TYPE_CONNECTION_TIMEOUT) {
610                 DEBUG(0, ("%s: Invalid command type received\n", __func__));
611                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
612                 return;
613         }
614
615         /* Extract connection timeout */
616         state->connection_timeout = rts.Commands[0].Command.ConnectionTimeout.ConnectionTimeout;
617
618         DEBUG(8, ("%s: CONN/A3 received, connection timeout is %u\n",
619                   __func__, state->connection_timeout));
620         tevent_req_done(req);
621 }
622
623 NTSTATUS roh_recv_CONN_A3_recv(struct tevent_req *req,
624                                unsigned int *connection_timeout)
625 {
626         NTSTATUS                        status;
627         struct roh_recv_pdu_state       *state;
628
629         state = tevent_req_data(req, struct roh_recv_pdu_state);
630         if (tevent_req_is_nterror(req, &status)) {
631                 tevent_req_received(req);
632                 return status;
633         }
634
635         *connection_timeout = state->connection_timeout;
636
637         tevent_req_received(req);
638         return NT_STATUS_OK;
639 }
640
641 static void roh_recv_CONN_C2_done(struct tevent_req *subreq);
642 struct tevent_req *roh_recv_CONN_C2_send(TALLOC_CTX *mem_ctx,
643                                          struct tevent_context *ev,
644                                          struct roh_connection *roh)
645 {
646         struct tevent_req               *req;
647         struct tevent_req               *subreq;
648         struct roh_recv_pdu_state       *state;
649
650         req = tevent_req_create(mem_ctx, &state, struct roh_recv_pdu_state);
651         if (req == NULL) {
652                 return NULL;
653         }
654
655         DEBUG(8, ("%s: Waiting for CONN/C2\n", __func__));
656         subreq = dcerpc_read_ncacn_packet_send(state, ev,
657                                                roh->default_channel_out->streams.active);
658         if (tevent_req_nomem(subreq, req)) {
659                 return tevent_req_post(req, ev);
660         }
661         tevent_req_set_callback(subreq, roh_recv_CONN_C2_done, req);
662
663         return req;
664 }
665
666 static void roh_recv_CONN_C2_done(struct tevent_req *subreq)
667 {
668         NTSTATUS                        status;
669         struct tevent_req               *req;
670         struct roh_recv_pdu_state       *state;
671         struct ncacn_packet             *pkt;
672         DATA_BLOB                       buffer;
673         struct dcerpc_rts               rts;
674
675         req = tevent_req_callback_data(subreq, struct tevent_req);
676         state = tevent_req_data(req, struct roh_recv_pdu_state);
677
678         status = dcerpc_read_ncacn_packet_recv(subreq, state, &pkt, &buffer);
679         TALLOC_FREE(subreq);
680         if (tevent_req_nterror(req, status)) {
681                 DEBUG(0, ("%s: Error receiving PDU\n", __func__));
682                 return;
683         }
684
685         /*
686          * Check if it is a CONN/C2 packet (2.2.4.9), and get the version, the
687          * receive windows size and the connection timeout for the IN channel
688          */
689         rts = pkt->u.rts;
690         if (rts.NumberOfCommands != 3) {
691                 DEBUG(0, ("%s: Invalid number of commands received\n",
692                           __func__));
693                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
694                 return;
695         }
696         if (rts.Commands[0].CommandType != ROH_CMD_TYPE_VERSION) {
697                 DEBUG(0, ("%s: Invalid command type received\n", __func__));
698                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
699                 return;
700         }
701         if (rts.Commands[1].CommandType != ROH_CMD_TYPE_RECV_WINDOWS_SIZE) {
702                 DEBUG(0, ("%s: Invalid command type received\n", __func__));
703                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
704                 return;
705         }
706         if (rts.Commands[2].CommandType != ROH_CMD_TYPE_CONNECTION_TIMEOUT) {
707                 DEBUG(0, ("%s: Invalid command type received\n", __func__));
708                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
709                 return;
710         }
711
712         /* Extract data */
713         state->version = rts.Commands[0].Command.Version.Version;
714         state->recv_window_size = rts.Commands[1].Command.ReceiveWindowSize.ReceiveWindowSize;
715         state->connection_timeout = rts.Commands[2].Command.ConnectionTimeout.ConnectionTimeout;
716
717         DEBUG(8, ("%s: CONN/C2 received, version is %u, receive windows size is %u, connection timeout is %u\n",
718                   __func__, state->version, state->recv_window_size,
719                   state->connection_timeout));
720         tevent_req_done(req);
721 }
722
723 NTSTATUS roh_recv_CONN_C2_recv(struct tevent_req *req,
724                                unsigned int *version,
725                                unsigned int *recv_window_size,
726                                unsigned int *connection_timeout)
727 {
728         NTSTATUS                        status;
729         struct roh_recv_pdu_state       *state;
730
731         if (tevent_req_is_nterror(req, &status)) {
732                 tevent_req_received(req);
733                 return status;
734         }
735
736         state =  tevent_req_data(req, struct roh_recv_pdu_state);
737         *version = state->version;
738         *recv_window_size = state->recv_window_size;
739         *connection_timeout = state->connection_timeout;
740
741         tevent_req_received(req);
742         return NT_STATUS_OK;
743 }