Line data Source code
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 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "lib/events/events.h"
24 : #include "lib/util/tevent_ntstatus.h"
25 : #include "lib/tls/tls.h"
26 : #include "libcli/resolve/resolve.h"
27 : #include "libcli/composite/composite.h"
28 : #include "auth/credentials/credentials.h"
29 : #include "tsocket/tsocket.h"
30 : #include "tsocket/tsocket_internal.h"
31 : #include "librpc/rpc/dcerpc.h"
32 : #include "librpc/rpc/dcerpc_roh.h"
33 : #include "librpc/rpc/dcerpc_proto.h"
34 : #include "lib/param/param.h"
35 : #include "libcli/http/http.h"
36 : #include "lib/util/util_net.h"
37 :
38 : static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream);
39 : static struct tevent_req * tstream_roh_readv_send(
40 : TALLOC_CTX *mem_ctx,
41 : struct tevent_context *ev,
42 : struct tstream_context *stream,
43 : struct iovec *vector,
44 : size_t count);
45 : static int tstream_roh_readv_recv(struct tevent_req *req, int *perrno);
46 : static struct tevent_req * tstream_roh_writev_send(
47 : TALLOC_CTX *mem_ctx,
48 : struct tevent_context *ev,
49 : struct tstream_context *stream,
50 : const struct iovec *vector,
51 : size_t count);
52 : static int tstream_roh_writev_recv(struct tevent_req *req, int *perrno);
53 : static struct tevent_req * tstream_roh_disconnect_send(
54 : TALLOC_CTX *mem_ctx,
55 : struct tevent_context *ev,
56 : struct tstream_context *stream);
57 : static int tstream_roh_disconnect_recv(struct tevent_req *req, int *perrno);
58 :
59 : static const struct tstream_context_ops tstream_roh_ops = {
60 : .name = "roh",
61 : .pending_bytes = tstream_roh_pending_bytes,
62 : .readv_send = tstream_roh_readv_send,
63 : .readv_recv = tstream_roh_readv_recv,
64 : .writev_send = tstream_roh_writev_send,
65 : .writev_recv = tstream_roh_writev_recv,
66 : .disconnect_send = tstream_roh_disconnect_send,
67 : .disconnect_recv = tstream_roh_disconnect_recv,
68 : };
69 :
70 : struct tstream_roh_context {
71 : struct roh_connection *roh_conn;
72 : };
73 :
74 : struct roh_open_connection_state {
75 : struct tevent_req *req;
76 : struct tevent_context *event_ctx;
77 : struct cli_credentials *credentials;
78 : struct resolve_context *resolve_ctx;
79 : const char **rpcproxy_addresses;
80 : unsigned int rpcproxy_address_index;
81 :
82 : struct dcecli_connection *conn;
83 : bool tls;
84 :
85 : const char *rpc_proxy;
86 : unsigned int rpc_proxy_port;
87 : const char *rpc_server;
88 : unsigned int rpc_server_port;
89 : const char *target_hostname;
90 :
91 : struct roh_connection *roh;
92 : struct tstream_tls_params *tls_params;
93 : struct loadparm_context *lp_ctx;
94 : uint8_t http_auth;
95 : };
96 :
97 0 : NTSTATUS dcerpc_pipe_open_roh_recv(struct tevent_req *req,
98 : TALLOC_CTX *mem_ctx,
99 : struct tstream_context **stream,
100 : struct tevent_queue **queue)
101 : {
102 0 : struct roh_open_connection_state *state;
103 0 : struct tstream_roh_context *roh_stream_ctx;
104 0 : NTSTATUS status;
105 :
106 0 : state = tevent_req_data(req, struct roh_open_connection_state);
107 0 : if (tevent_req_is_nterror(req, &status)) {
108 0 : tevent_req_received(req);
109 0 : return status;
110 : }
111 :
112 0 : *stream = tstream_context_create(mem_ctx, &tstream_roh_ops,
113 : &roh_stream_ctx,
114 : struct tstream_roh_context,
115 : __location__);
116 0 : if (!stream) {
117 0 : tevent_req_received(req);
118 0 : return NT_STATUS_NO_MEMORY;
119 : }
120 0 : ZERO_STRUCTP(roh_stream_ctx);
121 :
122 0 : roh_stream_ctx->roh_conn = talloc_move(mem_ctx, &state->roh);
123 0 : *queue = http_conn_send_queue(
124 0 : roh_stream_ctx->roh_conn->default_channel_in->http_conn);
125 :
126 0 : tevent_req_received(req);
127 :
128 0 : return NT_STATUS_OK;
129 : }
130 :
131 : struct roh_connect_channel_state {
132 : struct roh_channel *channel;
133 : };
134 :
135 : static void roh_connect_channel_done(struct tevent_req *subreq);
136 0 : static struct tevent_req *roh_connect_channel_send(TALLOC_CTX *mem_ctx,
137 : struct tevent_context *ev,
138 : const char *rpcproxy_ip_address,
139 : unsigned int rpcproxy_port,
140 : struct cli_credentials *credentials,
141 : bool tls,
142 : struct tstream_tls_params *tls_params)
143 : {
144 0 : struct tevent_req *req = NULL;
145 0 : struct tevent_req *subreq = NULL;
146 0 : struct roh_connect_channel_state *state = NULL;
147 :
148 0 : DBG_DEBUG("Connecting ROH channel socket, RPC proxy is "
149 : "%s:%d (TLS: %s)\n", rpcproxy_ip_address, rpcproxy_port,
150 : (tls ? "true" : "false"));
151 :
152 0 : req = tevent_req_create(mem_ctx, &state,
153 : struct roh_connect_channel_state);
154 0 : if (req == NULL) {
155 0 : return NULL;
156 : }
157 :
158 0 : if (!is_ipaddress(rpcproxy_ip_address)) {
159 0 : DBG_ERR("Invalid host (%s), needs to be an IP address\n",
160 : rpcproxy_ip_address);
161 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
162 0 : return tevent_req_post(req, ev);
163 : }
164 :
165 : /* Initialize channel structure */
166 0 : state->channel = talloc_zero(state, struct roh_channel);
167 0 : if (tevent_req_nomem(state->channel, req)) {
168 0 : return tevent_req_post(req, ev);
169 : }
170 :
171 0 : state->channel->channel_cookie = GUID_random();
172 :
173 0 : subreq = http_connect_send(state,
174 : ev,
175 : rpcproxy_ip_address,
176 : rpcproxy_port,
177 : credentials,
178 : tls ? tls_params : NULL);
179 0 : if (tevent_req_nomem(subreq, req)) {
180 0 : return tevent_req_post(req, ev);
181 : }
182 0 : tevent_req_set_callback(subreq, roh_connect_channel_done, req);
183 :
184 0 : return req;
185 : }
186 :
187 0 : static void roh_connect_channel_done(struct tevent_req *subreq)
188 : {
189 0 : struct tevent_req *req = NULL;
190 0 : struct roh_connect_channel_state *state = NULL;
191 0 : NTSTATUS status;
192 0 : int ret;
193 :
194 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
195 0 : state = tevent_req_data(req, struct roh_connect_channel_state);
196 :
197 0 : ret = http_connect_recv(subreq,
198 0 : state->channel,
199 0 : &state->channel->http_conn);
200 0 : TALLOC_FREE(subreq);
201 0 : if (ret != 0) {
202 0 : status = map_nt_error_from_unix_common(ret);
203 0 : tevent_req_nterror(req, status);
204 0 : return;
205 : }
206 :
207 0 : DBG_DEBUG("HTTP connected\n");
208 0 : tevent_req_done(req);
209 : }
210 :
211 0 : static NTSTATUS roh_connect_channel_recv(struct tevent_req *req,
212 : TALLOC_CTX *mem_ctx,
213 : struct roh_channel **channel)
214 : {
215 0 : struct roh_connect_channel_state *state = tevent_req_data(
216 : req, struct roh_connect_channel_state);
217 0 : NTSTATUS status;
218 :
219 0 : if (tevent_req_is_nterror(req, &status)) {
220 0 : tevent_req_received(req);
221 0 : return status;
222 : }
223 :
224 0 : *channel = talloc_move(mem_ctx, &state->channel);
225 0 : tevent_req_received(req);
226 :
227 0 : return NT_STATUS_OK;
228 : }
229 :
230 : static void roh_continue_resolve_name(struct composite_context *ctx);
231 :
232 : /**
233 : * Send rpc pipe open request to given host:port using http transport
234 : */
235 0 : struct tevent_req *dcerpc_pipe_open_roh_send(struct dcecli_connection *conn,
236 : const char *localaddr,
237 : const char *rpc_server,
238 : uint32_t rpc_server_port,
239 : const char *rpc_proxy,
240 : uint32_t rpc_proxy_port,
241 : const char *http_proxy,
242 : uint32_t http_proxy_port,
243 : bool use_tls,
244 : bool use_proxy,
245 : struct cli_credentials *credentials,
246 : struct resolve_context *resolve_ctx,
247 : struct loadparm_context *lp_ctx,
248 : uint8_t http_auth)
249 : {
250 0 : NTSTATUS status;
251 0 : struct tevent_req *req;
252 0 : struct composite_context *ctx;
253 0 : struct roh_open_connection_state *state;
254 0 : struct nbt_name name;
255 :
256 0 : req = tevent_req_create(conn, &state, struct roh_open_connection_state);
257 0 : if (req == NULL) {
258 0 : return NULL;
259 : }
260 :
261 : /* Set state fields */
262 0 : state->req = req;
263 0 : state->event_ctx = conn->event_ctx;
264 0 : state->lp_ctx = lp_ctx,
265 0 : state->credentials = credentials;
266 0 : state->conn = conn;
267 0 : state->tls = use_tls;
268 :
269 : /* Initialize connection structure (3.2.1.3) */
270 : /* TODO Initialize virtual connection cookie table */
271 0 : state->rpc_server = talloc_strdup(state, rpc_server);
272 0 : state->rpc_server_port = rpc_server_port;
273 0 : state->rpc_proxy = talloc_strdup(state, rpc_proxy);
274 0 : state->rpc_proxy_port = rpc_proxy_port;
275 0 : state->http_auth = http_auth;
276 :
277 0 : state->roh = talloc_zero(state, struct roh_connection);
278 0 : state->roh->protocol_version = ROH_V2;
279 0 : state->roh->connection_state = ROH_STATE_OPEN_START;
280 0 : state->roh->connection_cookie = GUID_random();
281 0 : state->roh->association_group_id_cookie = GUID_random();
282 :
283 : /* Additional initialization steps (3.2.2.3) */
284 0 : state->roh->proxy_use = use_proxy;
285 0 : state->roh->current_keep_alive_time = 0;
286 0 : state->roh->current_keep_alive_interval = 0;
287 :
288 : /* Initialize TLS */
289 0 : if (use_tls) {
290 0 : status = tstream_tls_params_client_lpcfg(state->roh,
291 : lp_ctx,
292 0 : state->rpc_proxy,
293 0 : &state->tls_params);
294 0 : if (!NT_STATUS_IS_OK(status)) {
295 0 : DBG_ERR("Failed tstream_tls_params_client_lpcfg - %s\n",
296 : nt_errstr(status));
297 0 : tevent_req_nterror(req, status);
298 0 : return tevent_req_post(req, conn->event_ctx);
299 : }
300 : }
301 :
302 : /* Resolve RPC proxy server name */
303 0 : make_nbt_name_server(&name, state->rpc_proxy);
304 0 : ctx = resolve_name_send(resolve_ctx, state, &name, state->event_ctx);
305 0 : if (tevent_req_nomem(ctx, req)) {
306 0 : return tevent_req_post(req, state->event_ctx);
307 : }
308 0 : ctx->async.fn = roh_continue_resolve_name;
309 0 : ctx->async.private_data = state;
310 :
311 0 : return req;
312 : }
313 :
314 : static void roh_connect_channel_in_done(struct tevent_req *subreq);
315 0 : static void roh_continue_resolve_name(struct composite_context *ctx)
316 : {
317 0 : NTSTATUS status;
318 0 : struct roh_open_connection_state *state;
319 0 : struct tevent_req *subreq;
320 :
321 0 : state = talloc_get_type_abort(ctx->async.private_data,
322 : struct roh_open_connection_state);
323 0 : status = resolve_name_multiple_recv(ctx, state,
324 : &state->rpcproxy_addresses);
325 0 : if (tevent_req_nterror(state->req, status)) {
326 0 : DEBUG(2, ("%s: No server found: %s\n", __func__,
327 : nt_errstr(status)));
328 0 : return;
329 : }
330 :
331 0 : state->rpcproxy_address_index = 0;
332 0 : if (state->rpcproxy_addresses[state->rpcproxy_address_index] == NULL) {
333 0 : DEBUG(2, ("%s: No server found\n", __func__));
334 0 : tevent_req_nterror(state->req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
335 0 : return;
336 : }
337 :
338 : /*
339 : * TODO Determine proxy use
340 : * If state->roh->proxy_use == true, the client has requested to
341 : * always use local proxy. Otherwise, run the proxy use discovery
342 : */
343 0 : state->roh->connection_state = ROH_STATE_OPEN_START;
344 0 : subreq = roh_connect_channel_send(state,
345 : state->event_ctx,
346 0 : state->rpcproxy_addresses[state->rpcproxy_address_index],
347 : state->rpc_proxy_port,
348 : state->credentials,
349 0 : state->tls,
350 : state->tls_params);
351 0 : if (tevent_req_nomem(subreq, state->req)) {
352 0 : return;
353 : }
354 0 : tevent_req_set_callback(subreq, roh_connect_channel_in_done, state->req);
355 : }
356 :
357 : static void roh_connect_channel_out_done(struct tevent_req *);
358 0 : static void roh_connect_channel_in_done(struct tevent_req *subreq)
359 : {
360 0 : NTSTATUS status;
361 0 : struct tevent_req *req;
362 0 : struct roh_open_connection_state *state;
363 :
364 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
365 0 : state = tevent_req_data(req, struct roh_open_connection_state);
366 :
367 0 : status = roh_connect_channel_recv(subreq, state->roh,
368 0 : &state->roh->default_channel_in);
369 0 : TALLOC_FREE(subreq);
370 0 : if (tevent_req_nterror(req, status)) {
371 0 : return;
372 : }
373 :
374 0 : subreq = roh_connect_channel_send(state,
375 : state->event_ctx,
376 0 : state->rpcproxy_addresses[state->rpcproxy_address_index],
377 : state->rpc_proxy_port,
378 : state->credentials,
379 0 : state->tls,
380 : state->tls_params);
381 0 : if (tevent_req_nomem(subreq, req)) {
382 0 : return;
383 : }
384 0 : tevent_req_set_callback(subreq, roh_connect_channel_out_done, req);
385 : }
386 :
387 : static void roh_send_RPC_DATA_IN_done(struct tevent_req *);
388 0 : static void roh_connect_channel_out_done(struct tevent_req *subreq)
389 : {
390 0 : NTSTATUS status;
391 0 : struct tevent_req *req;
392 0 : struct roh_open_connection_state *state;
393 :
394 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
395 0 : state = tevent_req_data(req, struct roh_open_connection_state);
396 :
397 0 : status = roh_connect_channel_recv(subreq, state->roh,
398 0 : &state->roh->default_channel_out);
399 0 : TALLOC_FREE(subreq);
400 0 : if (tevent_req_nterror(req, status)) {
401 0 : return;
402 : }
403 :
404 0 : subreq = roh_send_RPC_DATA_IN_send(state, state->lp_ctx,
405 : state->event_ctx,
406 : state->credentials,
407 : state->roh,
408 : state->rpc_server,
409 : state->rpc_server_port,
410 : state->rpc_proxy,
411 0 : state->http_auth);
412 0 : if (tevent_req_nomem(subreq, req)) {
413 0 : return;
414 : }
415 0 : tevent_req_set_callback(subreq, roh_send_RPC_DATA_IN_done, req);
416 : }
417 :
418 : static void roh_send_RPC_DATA_OUT_done(struct tevent_req *);
419 0 : static void roh_send_RPC_DATA_IN_done(struct tevent_req *subreq)
420 : {
421 0 : NTSTATUS status;
422 0 : struct tevent_req *req;
423 0 : struct roh_open_connection_state *state;
424 :
425 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
426 0 : state = tevent_req_data(req, struct roh_open_connection_state);
427 :
428 0 : status = roh_send_RPC_DATA_IN_recv(subreq);
429 0 : TALLOC_FREE(subreq);
430 0 : if (tevent_req_nterror(req, status)) {
431 0 : return;
432 : }
433 :
434 0 : subreq = roh_send_RPC_DATA_OUT_send(state,
435 : state->lp_ctx,
436 : state->event_ctx,
437 : state->credentials,
438 : state->roh,
439 : state->rpc_server,
440 : state->rpc_server_port,
441 : state->rpc_proxy,
442 0 : state->http_auth);
443 0 : if (tevent_req_nomem(subreq, req)) {
444 0 : return;
445 : }
446 0 : tevent_req_set_callback(subreq, roh_send_RPC_DATA_OUT_done, req);
447 : }
448 :
449 : static void roh_send_CONN_A1_done(struct tevent_req *);
450 0 : static void roh_send_RPC_DATA_OUT_done(struct tevent_req *subreq)
451 : {
452 0 : NTSTATUS status;
453 0 : struct tevent_req *req;
454 0 : struct roh_open_connection_state *state;
455 :
456 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
457 0 : state = tevent_req_data(req, struct roh_open_connection_state);
458 :
459 0 : status = roh_send_RPC_DATA_OUT_recv(subreq);
460 0 : TALLOC_FREE(subreq);
461 0 : if (tevent_req_nterror(req, status)) {
462 0 : return;
463 : }
464 :
465 0 : subreq = roh_send_CONN_A1_send(state, state->event_ctx, state->roh);
466 0 : if (tevent_req_nomem(subreq, req)) {
467 0 : return;
468 : }
469 0 : tevent_req_set_callback(subreq, roh_send_CONN_A1_done, req);
470 : }
471 :
472 : static void roh_send_CONN_B1_done(struct tevent_req *);
473 0 : static void roh_send_CONN_A1_done(struct tevent_req *subreq)
474 : {
475 0 : NTSTATUS status;
476 0 : struct tevent_req *req;
477 0 : struct roh_open_connection_state *state;
478 :
479 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
480 0 : state = tevent_req_data(req, struct roh_open_connection_state);
481 :
482 0 : status = roh_send_CONN_A1_recv(subreq);
483 0 : TALLOC_FREE(subreq);
484 0 : if (tevent_req_nterror(req, status)) {
485 0 : return;
486 : }
487 :
488 0 : subreq = roh_send_CONN_B1_send(state, state->event_ctx, state->roh);
489 0 : if (tevent_req_nomem(subreq, req)) {
490 0 : return;
491 : }
492 0 : tevent_req_set_callback(subreq, roh_send_CONN_B1_done, req);
493 : }
494 :
495 : static void roh_recv_out_channel_response_done(struct tevent_req *);
496 0 : static void roh_send_CONN_B1_done(struct tevent_req *subreq)
497 : {
498 0 : NTSTATUS status;
499 0 : struct tevent_req *req;
500 0 : struct roh_open_connection_state *state;
501 :
502 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
503 0 : state = tevent_req_data(req, struct roh_open_connection_state);
504 :
505 0 : status = roh_send_CONN_B1_recv(subreq);
506 0 : TALLOC_FREE(subreq);
507 0 : if (tevent_req_nterror(req, status)) {
508 0 : return;
509 : }
510 :
511 0 : state->roh->connection_state = ROH_STATE_OUT_CHANNEL_WAIT;
512 0 : subreq = roh_recv_out_channel_response_send(state, state->event_ctx,
513 : state->roh);
514 0 : if (tevent_req_nomem(subreq, req)) {
515 0 : return;
516 : }
517 0 : tevent_req_set_callback(subreq, roh_recv_out_channel_response_done, req);
518 : }
519 :
520 : static void roh_recv_CONN_A3_done(struct tevent_req *);
521 0 : static void roh_recv_out_channel_response_done(struct tevent_req *subreq)
522 : {
523 0 : NTSTATUS status;
524 0 : char *response;
525 0 : struct tevent_req *req;
526 0 : struct roh_open_connection_state *state;
527 :
528 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
529 0 : state = tevent_req_data(req, struct roh_open_connection_state);
530 :
531 0 : status = roh_recv_out_channel_response_recv(subreq, state, &response);
532 0 : TALLOC_FREE(subreq);
533 0 : if (tevent_req_nterror(req, status)) {
534 0 : return;
535 : }
536 :
537 0 : state->roh->connection_state = ROH_STATE_WAIT_A3W;
538 0 : subreq = roh_recv_CONN_A3_send(state, state->event_ctx, state->roh);
539 0 : if (tevent_req_nomem(subreq, req)) {
540 0 : return;
541 : }
542 0 : tevent_req_set_callback(subreq, roh_recv_CONN_A3_done, req);
543 : }
544 :
545 : static void roh_recv_CONN_C2_done(struct tevent_req *);
546 0 : static void roh_recv_CONN_A3_done(struct tevent_req *subreq)
547 : {
548 0 : NTSTATUS status;
549 0 : struct tevent_req *req;
550 0 : struct roh_open_connection_state *state;
551 :
552 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
553 0 : state = tevent_req_data(req, struct roh_open_connection_state);
554 :
555 0 : status = roh_recv_CONN_A3_recv(subreq, &state->roh->default_channel_out->connection_timeout);
556 0 : TALLOC_FREE(subreq);
557 0 : if (tevent_req_nterror(req, status)) {
558 0 : return;
559 : }
560 :
561 0 : state->roh->connection_state = ROH_STATE_WAIT_C2;
562 0 : subreq = roh_recv_CONN_C2_send(state, state->event_ctx, state->roh);
563 0 : if (tevent_req_nomem(subreq, req)) {
564 0 : return;
565 : }
566 0 : tevent_req_set_callback(subreq, roh_recv_CONN_C2_done, req);
567 : }
568 :
569 0 : static void roh_recv_CONN_C2_done(struct tevent_req *subreq)
570 : {
571 0 : NTSTATUS status;
572 0 : struct tevent_req *req;
573 0 : struct roh_open_connection_state *state;
574 0 : unsigned int version;
575 0 : unsigned int recv;
576 0 : unsigned int timeout;
577 :
578 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
579 0 : state = tevent_req_data(req, struct roh_open_connection_state);
580 :
581 0 : status = roh_recv_CONN_C2_recv(subreq, &version, &recv, &timeout);
582 0 : TALLOC_FREE(subreq);
583 0 : if (tevent_req_nterror(req, status)) {
584 0 : return;
585 : }
586 0 : state->roh->connection_state = ROH_STATE_OPENED;
587 :
588 0 : tevent_req_done(req);
589 : }
590 :
591 0 : static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream)
592 : {
593 0 : struct tstream_roh_context *ctx = NULL;
594 0 : struct tstream_context *tstream = NULL;
595 :
596 0 : ctx = tstream_context_data(stream, struct tstream_roh_context);
597 0 : if (!ctx->roh_conn) {
598 0 : errno = ENOTCONN;
599 0 : return -1;
600 : }
601 :
602 0 : tstream = http_conn_tstream(
603 0 : ctx->roh_conn->default_channel_out->http_conn);
604 0 : if (tstream == NULL) {
605 0 : errno = ENOTCONN;
606 0 : return -1;
607 : }
608 0 : return tstream_pending_bytes(tstream);
609 : }
610 :
611 : struct tstream_roh_readv_state {
612 : struct roh_connection *roh_conn;
613 : int ret;
614 : };
615 :
616 : static void tstream_roh_readv_handler(struct tevent_req *subreq);
617 0 : static struct tevent_req * tstream_roh_readv_send(TALLOC_CTX *mem_ctx,
618 : struct tevent_context *ev,
619 : struct tstream_context *stream,
620 : struct iovec *vector,
621 : size_t count)
622 : {
623 0 : struct tstream_roh_context *ctx = NULL;
624 0 : struct tstream_roh_readv_state *state;
625 0 : struct tevent_req *req, *subreq;
626 0 : struct tstream_context *channel_stream = NULL;
627 :
628 0 : req = tevent_req_create(mem_ctx, &state, struct tstream_roh_readv_state);
629 0 : if (!req) {
630 0 : return NULL;
631 : }
632 :
633 0 : ctx = tstream_context_data(stream, struct tstream_roh_context);
634 0 : if (!ctx->roh_conn) {
635 0 : tevent_req_error(req, ENOTCONN);
636 0 : goto post;
637 : }
638 0 : if (!ctx->roh_conn->default_channel_out) {
639 0 : tevent_req_error(req, ENOTCONN);
640 0 : goto post;
641 : }
642 0 : channel_stream = http_conn_tstream(
643 0 : ctx->roh_conn->default_channel_out->http_conn);
644 0 : if (channel_stream == NULL) {
645 0 : tevent_req_error(req, ENOTCONN);
646 0 : goto post;
647 : }
648 :
649 0 : state->roh_conn = ctx->roh_conn;
650 :
651 0 : subreq = tstream_readv_send(state, ev,
652 : channel_stream,
653 : vector, count);
654 0 : if (tevent_req_nomem(subreq, req)) {
655 0 : goto post;
656 : }
657 0 : tevent_req_set_callback(subreq, tstream_roh_readv_handler, req);
658 :
659 0 : return req;
660 0 : post:
661 0 : tevent_req_post(req, ev);
662 0 : return req;
663 : }
664 :
665 0 : static void tstream_roh_readv_handler(struct tevent_req *subreq)
666 : {
667 0 : struct tevent_req *req;
668 0 : struct tstream_roh_readv_state *state;
669 0 : int ret;
670 0 : int sys_errno;
671 :
672 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
673 0 : state = tevent_req_data(req, struct tstream_roh_readv_state);
674 0 : ret = tstream_readv_recv(subreq, &sys_errno);
675 0 : TALLOC_FREE(subreq);
676 0 : if (ret == -1) {
677 0 : tevent_req_error(req, sys_errno);
678 0 : return;
679 : }
680 :
681 0 : state->ret = ret;
682 :
683 0 : tevent_req_done(req);
684 : }
685 :
686 0 : static int tstream_roh_readv_recv(struct tevent_req *req, int *perrno)
687 : {
688 0 : struct tstream_roh_readv_state *state;
689 0 : int ret;
690 :
691 0 : state = tevent_req_data(req, struct tstream_roh_readv_state);
692 0 : ret = tsocket_simple_int_recv(req, perrno);
693 0 : if (ret == 0) {
694 0 : ret = state->ret;
695 : }
696 :
697 0 : tevent_req_received(req);
698 0 : return ret;
699 : }
700 :
701 : struct tstream_roh_writev_state {
702 : struct roh_connection *roh_conn;
703 : int nwritten;
704 : };
705 :
706 : static void tstream_roh_writev_handler(struct tevent_req *subreq);
707 0 : static struct tevent_req * tstream_roh_writev_send(TALLOC_CTX *mem_ctx,
708 : struct tevent_context *ev,
709 : struct tstream_context *stream,
710 : const struct iovec *vector,
711 : size_t count)
712 : {
713 0 : struct tstream_roh_context *ctx = NULL;
714 0 : struct tstream_roh_writev_state *state = NULL;
715 0 : struct tevent_req *req = NULL;
716 0 : struct tevent_req *subreq = NULL;
717 0 : struct tstream_context *channel_stream = NULL;
718 :
719 0 : req = tevent_req_create(mem_ctx, &state,
720 : struct tstream_roh_writev_state);
721 0 : if (!req) {
722 0 : return NULL;
723 : }
724 :
725 0 : ctx = tstream_context_data(stream, struct tstream_roh_context);
726 0 : if (!ctx->roh_conn) {
727 0 : tevent_req_error(req, ENOTCONN);
728 0 : goto post;
729 : }
730 0 : if (!ctx->roh_conn->default_channel_in) {
731 0 : tevent_req_error(req, ENOTCONN);
732 0 : goto post;
733 : }
734 0 : channel_stream = http_conn_tstream(
735 0 : ctx->roh_conn->default_channel_in->http_conn);
736 0 : if (channel_stream == NULL) {
737 0 : tevent_req_error(req, ENOTCONN);
738 0 : goto post;
739 : }
740 :
741 0 : state->roh_conn = ctx->roh_conn;
742 :
743 0 : subreq = tstream_writev_send(state, ev,
744 : channel_stream,
745 : vector, count);
746 0 : if (tevent_req_nomem(subreq, req)) {
747 0 : goto post;
748 : }
749 0 : tevent_req_set_callback(subreq, tstream_roh_writev_handler, req);
750 :
751 0 : return req;
752 0 : post:
753 0 : tevent_req_post(req, ev);
754 0 : return req;
755 : }
756 :
757 0 : static void tstream_roh_writev_handler(struct tevent_req *subreq)
758 : {
759 0 : struct tevent_req *req;
760 0 : struct tstream_roh_writev_state *state;
761 0 : int nwritten;
762 0 : int sys_errno;
763 :
764 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
765 0 : state = tevent_req_data(req, struct tstream_roh_writev_state);
766 0 : nwritten = tstream_writev_recv(subreq, &sys_errno);
767 0 : TALLOC_FREE(subreq);
768 0 : if (nwritten == -1) {
769 0 : tevent_req_error(req, sys_errno);
770 0 : return;
771 : }
772 0 : state->nwritten = nwritten;
773 0 : state->roh_conn->default_channel_in->sent_bytes += nwritten;
774 :
775 0 : tevent_req_done(req);
776 : }
777 :
778 0 : static int tstream_roh_writev_recv(struct tevent_req *req, int *perrno)
779 : {
780 0 : struct tstream_roh_writev_state *state;
781 0 : int ret;
782 :
783 0 : state = tevent_req_data(req, struct tstream_roh_writev_state);
784 0 : ret = tsocket_simple_int_recv(req, perrno);
785 0 : if (ret == 0) {
786 0 : ret = state->nwritten;
787 : }
788 :
789 0 : return ret;
790 : }
791 :
792 : struct tstream_roh_disconnect_state {
793 : struct tstream_context *stream;
794 : struct tevent_context *ev;
795 : };
796 :
797 : static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq);
798 0 : static struct tevent_req * tstream_roh_disconnect_send(TALLOC_CTX *mem_ctx,
799 : struct tevent_context *ev,
800 : struct tstream_context *stream)
801 : {
802 0 : struct tstream_roh_context *ctx = NULL;
803 0 : struct tevent_req *req, *subreq;
804 0 : struct tstream_roh_disconnect_state *state;
805 :
806 0 : req = tevent_req_create(mem_ctx, &state, struct tstream_roh_disconnect_state);
807 0 : if (req == NULL) {
808 0 : return NULL;
809 : }
810 :
811 0 : state->stream = stream;
812 0 : state->ev = ev;
813 :
814 0 : ctx = tstream_context_data(stream, struct tstream_roh_context);
815 0 : if (!ctx->roh_conn) {
816 0 : tevent_req_error(req, ENOTCONN);
817 0 : goto post;
818 : }
819 0 : if (!ctx->roh_conn->default_channel_in) {
820 0 : tevent_req_error(req, ENOTCONN);
821 0 : goto post;
822 : }
823 :
824 0 : subreq = http_disconnect_send(
825 : state,
826 : ev,
827 0 : ctx->roh_conn->default_channel_in->http_conn);
828 0 : if (tevent_req_nomem(subreq, req)) {
829 0 : goto post;
830 : }
831 0 : tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_in_handler, req);
832 :
833 0 : return req;
834 0 : post:
835 0 : tevent_req_post(req, ev);
836 0 : return req;
837 : }
838 :
839 : static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq);
840 :
841 0 : static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq)
842 : {
843 0 : struct tevent_req *req;
844 0 : struct tstream_roh_disconnect_state *state;
845 0 : struct tstream_context *stream;
846 0 : struct tstream_roh_context *roh_stream;
847 0 : int ret;
848 :
849 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
850 0 : state = tevent_req_data(req, struct tstream_roh_disconnect_state);
851 0 : stream = state->stream;
852 0 : roh_stream = tstream_context_data(stream, struct tstream_roh_context);
853 :
854 0 : ret = http_disconnect_recv(subreq);
855 0 : TALLOC_FREE(subreq);
856 0 : if (ret != 0) {
857 0 : tevent_req_error(req, ret);
858 0 : return;
859 : }
860 0 : TALLOC_FREE(roh_stream->roh_conn->default_channel_in);
861 :
862 0 : subreq = http_disconnect_send(
863 : state,
864 : state->ev,
865 0 : roh_stream->roh_conn->default_channel_out->http_conn);
866 0 : if (tevent_req_nomem(subreq, req)) {
867 0 : return;
868 : }
869 0 : tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_out_handler, req);
870 :
871 0 : return;
872 : }
873 :
874 0 : static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq)
875 : {
876 0 : struct tevent_req *req;
877 0 : struct tstream_roh_disconnect_state *state;
878 0 : struct tstream_context *stream;
879 0 : struct tstream_roh_context *roh_stream;
880 0 : int ret;
881 :
882 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
883 0 : state = tevent_req_data(req, struct tstream_roh_disconnect_state);
884 0 : stream = state->stream;
885 0 : roh_stream = tstream_context_data(stream, struct tstream_roh_context);
886 :
887 0 : ret = http_disconnect_recv(subreq);
888 0 : TALLOC_FREE(subreq);
889 0 : if (ret != 0) {
890 0 : tevent_req_error(req, ret);
891 0 : return;
892 : }
893 0 : TALLOC_FREE(roh_stream->roh_conn->default_channel_out);
894 :
895 0 : tevent_req_done(req);
896 : }
897 :
898 0 : static int tstream_roh_disconnect_recv(struct tevent_req *req, int *perrno)
899 : {
900 0 : int ret;
901 :
902 0 : ret = tsocket_simple_int_recv(req, perrno);
903 0 : tevent_req_received(req);
904 :
905 0 : return ret;
906 : }
|