build: Remove build of replacetort
[Samba.git] / source4 / librpc / rpc / dcerpc_roh_channel_out.c
blob23cbce3022d9731211b32a3d5106100487737fb9
1 /*
2 Unix SMB/CIFS implementation.
4 [MS-RPCH] - RPC over HTTP client
6 Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
7 Copyright (C) Julien Kerihuel <j.kerihuel@openchange.org> 2013
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.
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.
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/>.
23 #include "includes.h"
24 #include <tevent.h>
25 #include <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>
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"
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;
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)
62 NTSTATUS status;
63 struct tevent_req *req;
64 struct tevent_req *subreq;
65 struct roh_connect_channel_state *state;
66 int ret;
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")));
72 req = tevent_req_create(mem_ctx, &state, struct roh_connect_channel_state);
73 if (req == NULL) {
74 return NULL;
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);
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);
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);
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);
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);
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);
130 tevent_req_set_callback(subreq, roh_connect_channel_out_done, req);
132 return req;
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)
138 NTSTATUS status;
139 struct tevent_req *req;
140 struct roh_connect_channel_state *state;
141 int ret;
142 int sys_errno;
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;
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;
170 tevent_req_set_callback(subreq, roh_connect_channel_out_tls_done, req);
171 return;
174 tevent_req_done(req);
177 static void roh_connect_channel_out_tls_done(struct tevent_req *subreq)
179 NTSTATUS status;
180 struct tevent_req *req;
181 struct roh_connect_channel_state *state;
182 int ret;
183 int sys_errno;
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;
198 DEBUG(8, ("%s: TLS handshake completed\n", __func__));
200 tevent_req_done(req);
203 NTSTATUS roh_connect_channel_out_recv(struct tevent_req *req)
205 NTSTATUS status;
207 if (tevent_req_is_nterror(req, &status)) {
208 tevent_req_received(req);
209 return status;
212 tevent_req_received(req);
213 return NT_STATUS_OK;
216 struct roh_request_state {
217 struct http_request *request;
218 struct http_request *response;
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)
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;
239 DEBUG(8, ("%s: Sending RPC_OUT_DATA request\n", __func__));
241 req = tevent_req_create(mem_ctx, &state, struct roh_request_state);
242 if (req == NULL) {
243 return NULL;
246 state->request = talloc_zero(state, struct http_request);
247 if (tevent_req_nomem(state->request, req)) {
248 return tevent_req_post(req, ev);
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);
258 * TODO This path changes to "/rpcwithcert/rpcproxy.dll" when using
259 * certificates
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);
267 TALLOC_FREE(query);
270 * Create the HTTP channel OUT request as specified in the
271 * section 2.1.2.1.2
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';
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");
295 subreq = http_send_auth_request_send(state,
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);
306 tevent_req_set_callback(subreq, roh_send_RPC_DATA_OUT_done, req);
308 return req;
311 static void roh_send_RPC_DATA_OUT_done(struct tevent_req *subreq)
313 NTSTATUS status;
314 struct tevent_req *req;
316 req = tevent_req_callback_data(subreq, struct tevent_req);
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;
325 DEBUG(8, ("%s: RPC_OUT_DATA sent", __func__));
327 tevent_req_done(req);
330 NTSTATUS roh_send_RPC_DATA_OUT_recv(struct tevent_req *req)
332 NTSTATUS status;
334 if (tevent_req_is_nterror(req, &status)) {
335 tevent_req_received(req);
336 return status;
339 tevent_req_received(req);
340 return NT_STATUS_OK;
343 struct roh_send_pdu_state {
344 DATA_BLOB buffer;
345 struct iovec iov;
346 int bytes_written;
347 int sys_errno;
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)
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;
362 DEBUG(8, ("%s: Sending CONN/A1 request\n", __func__));
364 req = tevent_req_create(mem_ctx, &state, struct roh_send_pdu_state);
365 if (req == NULL) {
366 return NULL;
369 rts.Flags = RTS_FLAG_NONE;
370 rts.NumberOfCommands = 4;
371 rts.Commands = talloc_array(state, struct dcerpc_rts_cmd, 4);
373 /* CONN/A1: Version RTS command */
374 rts.Commands[0].CommandType = 0x00000006;
375 rts.Commands[0].Command.Version.Version = 0x00000001;
377 /* CONN/A1: VirtualConnectionCookie RTS command */
378 rts.Commands[1].CommandType = 0x00000003;
379 rts.Commands[1].Command.Cookie.Cookie.Cookie = roh->connection_cookie;
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;
386 /* CONN/A1: ReceiveWindowSize */
387 rts.Commands[3].CommandType = 0x00000000;
388 rts.Commands[3].Command.ReceiveWindowSize.ReceiveWindowSize = 0x40000;
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;
403 ndr = ndr_push_init_ctx(state);
404 ndr->offset = 0;
405 ndr_push_ncacn_packet(ndr, NDR_SCALARS, &pkt);
407 state->buffer = ndr_push_blob(ndr);
408 state->iov.iov_base = (char *) state->buffer.data;
409 state->iov.iov_len = state->buffer.length;
411 subreq = tstream_writev_queue_send(mem_ctx,
413 roh->default_channel_out->streams.active,
414 roh->default_channel_out->send_queue,
415 &state->iov,
417 if (tevent_req_nomem(subreq, req)) {
418 return tevent_req_post(req, ev);
420 tevent_req_set_callback(subreq, roh_send_CONN_A1_done, req);
422 return req;
425 static void roh_send_CONN_A1_done(struct tevent_req *subreq)
427 NTSTATUS status;
428 struct tevent_req *req;
429 struct roh_send_pdu_state *state;
430 int sys_errno;
432 req = tevent_req_callback_data(subreq, struct tevent_req);
433 state = tevent_req_data(req, struct roh_send_pdu_state);
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;
443 DEBUG(8, ("%s: CONN/A1 sent (%d bytes written)\n",
444 __func__, state->bytes_written));
446 tevent_req_done(req);
449 NTSTATUS roh_send_CONN_A1_recv(struct tevent_req *req)
451 NTSTATUS status;
453 if (tevent_req_is_nterror(req, &status)) {
454 tevent_req_received(req);
455 return status;
458 tevent_req_received(req);
459 return NT_STATUS_OK;
462 struct roh_recv_response_state
464 struct http_request *response;
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)
472 struct tevent_req *req;
473 struct tevent_req *subreq;
474 struct roh_recv_response_state *state;
476 DEBUG(8, ("%s: Waiting for RPC_OUT_DATA response\n", __func__));
478 req = tevent_req_create(mem_ctx, &state, struct roh_recv_response_state);
479 if (req == NULL) {
480 return NULL;
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);
489 tevent_req_set_callback(subreq, roh_recv_out_channel_response_done, req);
491 return req;
494 static void roh_recv_out_channel_response_done(struct tevent_req *subreq)
496 NTSTATUS status;
497 struct tevent_req *req;
498 struct roh_recv_response_state *state;
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;
508 DEBUG(8, ("%s: RCP_OUT_DATA response received\n", __func__));
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;
529 tevent_req_done(req);
532 NTSTATUS roh_recv_out_channel_response_recv(struct tevent_req *req,
533 TALLOC_CTX *mem_ctx,
534 char **response_msg)
536 NTSTATUS status;
538 if (tevent_req_is_nterror(req, &status)) {
539 tevent_req_received(req);
540 return status;
543 tevent_req_received(req);
544 return NT_STATUS_OK;
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;
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)
559 struct tevent_req *req;
560 struct tevent_req *subreq;
561 struct roh_recv_pdu_state *state;
563 req = tevent_req_create(mem_ctx, &state, struct roh_recv_pdu_state);
564 if (req == NULL) {
565 return NULL;
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);
574 tevent_req_set_callback(subreq, roh_recv_CONN_A3_done, req);
576 return req;
579 static void roh_recv_CONN_A3_done(struct tevent_req *subreq)
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;
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);
593 if (tevent_req_nterror(req, status)) {
594 DEBUG(0, ("%s: Error receiving PDU\n", __func__));
595 return;
599 * Check if it is a CONN/A3 (2.2.4.4) packet and get the connection
600 * timeout
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;
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;
615 /* Extract connection timeout */
616 state->connection_timeout = rts.Commands[0].Command.ConnectionTimeout.ConnectionTimeout;
618 DEBUG(8, ("%s: CONN/A3 received, connection timeout is %u\n",
619 __func__, state->connection_timeout));
620 tevent_req_done(req);
623 NTSTATUS roh_recv_CONN_A3_recv(struct tevent_req *req,
624 unsigned int *connection_timeout)
626 NTSTATUS status;
627 struct roh_recv_pdu_state *state;
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;
635 *connection_timeout = state->connection_timeout;
637 tevent_req_received(req);
638 return NT_STATUS_OK;
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)
646 struct tevent_req *req;
647 struct tevent_req *subreq;
648 struct roh_recv_pdu_state *state;
650 req = tevent_req_create(mem_ctx, &state, struct roh_recv_pdu_state);
651 if (req == NULL) {
652 return NULL;
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);
661 tevent_req_set_callback(subreq, roh_recv_CONN_C2_done, req);
663 return req;
666 static void roh_recv_CONN_C2_done(struct tevent_req *subreq)
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;
675 req = tevent_req_callback_data(subreq, struct tevent_req);
676 state = tevent_req_data(req, struct roh_recv_pdu_state);
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;
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
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;
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;
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;
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;
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;
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);
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)
728 NTSTATUS status;
729 struct roh_recv_pdu_state *state;
731 if (tevent_req_is_nterror(req, &status)) {
732 tevent_req_received(req);
733 return status;
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;
741 tevent_req_received(req);
742 return NT_STATUS_OK;