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 : char *ca_file = lpcfg_tls_cafile(state, lp_ctx);
291 0 : char *crl_file = lpcfg_tls_crlfile(state, lp_ctx);
292 0 : const char *tls_priority = lpcfg_tls_priority(lp_ctx);
293 0 : enum tls_verify_peer_state verify_peer =
294 0 : lpcfg_tls_verify_peer(lp_ctx);
295 :
296 0 : status = tstream_tls_params_client(state->roh,
297 : ca_file, crl_file,
298 : tls_priority,
299 : verify_peer,
300 0 : state->rpc_proxy,
301 0 : &state->tls_params);
302 0 : if (!NT_STATUS_IS_OK(status)) {
303 0 : DEBUG(0,("%s: Failed tstream_tls_params_client - %s\n",
304 : __func__, nt_errstr(status)));
305 0 : tevent_req_nterror(req, status);
306 0 : return tevent_req_post(req, conn->event_ctx);
307 : }
308 : }
309 :
310 : /* Resolve RPC proxy server name */
311 0 : make_nbt_name_server(&name, state->rpc_proxy);
312 0 : ctx = resolve_name_send(resolve_ctx, state, &name, state->event_ctx);
313 0 : if (tevent_req_nomem(ctx, req)) {
314 0 : return tevent_req_post(req, state->event_ctx);
315 : }
316 0 : ctx->async.fn = roh_continue_resolve_name;
317 0 : ctx->async.private_data = state;
318 :
319 0 : return req;
320 : }
321 :
322 : static void roh_connect_channel_in_done(struct tevent_req *subreq);
323 0 : static void roh_continue_resolve_name(struct composite_context *ctx)
324 : {
325 0 : NTSTATUS status;
326 0 : struct roh_open_connection_state *state;
327 0 : struct tevent_req *subreq;
328 :
329 0 : state = talloc_get_type_abort(ctx->async.private_data,
330 : struct roh_open_connection_state);
331 0 : status = resolve_name_multiple_recv(ctx, state,
332 : &state->rpcproxy_addresses);
333 0 : if (tevent_req_nterror(state->req, status)) {
334 0 : DEBUG(2, ("%s: No server found: %s\n", __func__,
335 : nt_errstr(status)));
336 0 : return;
337 : }
338 :
339 0 : state->rpcproxy_address_index = 0;
340 0 : if (state->rpcproxy_addresses[state->rpcproxy_address_index] == NULL) {
341 0 : DEBUG(2, ("%s: No server found\n", __func__));
342 0 : tevent_req_nterror(state->req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
343 0 : return;
344 : }
345 :
346 : /*
347 : * TODO Determine proxy use
348 : * If state->roh->proxy_use == true, the client has requested to
349 : * always use local proxy. Otherwise, run the proxy use discovery
350 : */
351 0 : state->roh->connection_state = ROH_STATE_OPEN_START;
352 0 : subreq = roh_connect_channel_send(state,
353 : state->event_ctx,
354 0 : state->rpcproxy_addresses[state->rpcproxy_address_index],
355 : state->rpc_proxy_port,
356 : state->credentials,
357 0 : state->tls,
358 : state->tls_params);
359 0 : if (tevent_req_nomem(subreq, state->req)) {
360 0 : return;
361 : }
362 0 : tevent_req_set_callback(subreq, roh_connect_channel_in_done, state->req);
363 : }
364 :
365 : static void roh_connect_channel_out_done(struct tevent_req *);
366 0 : static void roh_connect_channel_in_done(struct tevent_req *subreq)
367 : {
368 0 : NTSTATUS status;
369 0 : struct tevent_req *req;
370 0 : struct roh_open_connection_state *state;
371 :
372 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
373 0 : state = tevent_req_data(req, struct roh_open_connection_state);
374 :
375 0 : status = roh_connect_channel_recv(subreq, state->roh,
376 0 : &state->roh->default_channel_in);
377 0 : TALLOC_FREE(subreq);
378 0 : if (tevent_req_nterror(req, status)) {
379 0 : return;
380 : }
381 :
382 0 : subreq = roh_connect_channel_send(state,
383 : state->event_ctx,
384 0 : state->rpcproxy_addresses[state->rpcproxy_address_index],
385 : state->rpc_proxy_port,
386 : state->credentials,
387 0 : state->tls,
388 : state->tls_params);
389 0 : if (tevent_req_nomem(subreq, req)) {
390 0 : return;
391 : }
392 0 : tevent_req_set_callback(subreq, roh_connect_channel_out_done, req);
393 : }
394 :
395 : static void roh_send_RPC_DATA_IN_done(struct tevent_req *);
396 0 : static void roh_connect_channel_out_done(struct tevent_req *subreq)
397 : {
398 0 : NTSTATUS status;
399 0 : struct tevent_req *req;
400 0 : struct roh_open_connection_state *state;
401 :
402 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
403 0 : state = tevent_req_data(req, struct roh_open_connection_state);
404 :
405 0 : status = roh_connect_channel_recv(subreq, state->roh,
406 0 : &state->roh->default_channel_out);
407 0 : TALLOC_FREE(subreq);
408 0 : if (tevent_req_nterror(req, status)) {
409 0 : return;
410 : }
411 :
412 0 : subreq = roh_send_RPC_DATA_IN_send(state, state->lp_ctx,
413 : state->event_ctx,
414 : state->credentials,
415 : state->roh,
416 : state->rpc_server,
417 : state->rpc_server_port,
418 : state->rpc_proxy,
419 0 : state->http_auth);
420 0 : if (tevent_req_nomem(subreq, req)) {
421 0 : return;
422 : }
423 0 : tevent_req_set_callback(subreq, roh_send_RPC_DATA_IN_done, req);
424 : }
425 :
426 : static void roh_send_RPC_DATA_OUT_done(struct tevent_req *);
427 0 : static void roh_send_RPC_DATA_IN_done(struct tevent_req *subreq)
428 : {
429 0 : NTSTATUS status;
430 0 : struct tevent_req *req;
431 0 : struct roh_open_connection_state *state;
432 :
433 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
434 0 : state = tevent_req_data(req, struct roh_open_connection_state);
435 :
436 0 : status = roh_send_RPC_DATA_IN_recv(subreq);
437 0 : TALLOC_FREE(subreq);
438 0 : if (tevent_req_nterror(req, status)) {
439 0 : return;
440 : }
441 :
442 0 : subreq = roh_send_RPC_DATA_OUT_send(state,
443 : state->lp_ctx,
444 : state->event_ctx,
445 : state->credentials,
446 : state->roh,
447 : state->rpc_server,
448 : state->rpc_server_port,
449 : state->rpc_proxy,
450 0 : state->http_auth);
451 0 : if (tevent_req_nomem(subreq, req)) {
452 0 : return;
453 : }
454 0 : tevent_req_set_callback(subreq, roh_send_RPC_DATA_OUT_done, req);
455 : }
456 :
457 : static void roh_send_CONN_A1_done(struct tevent_req *);
458 0 : static void roh_send_RPC_DATA_OUT_done(struct tevent_req *subreq)
459 : {
460 0 : NTSTATUS status;
461 0 : struct tevent_req *req;
462 0 : struct roh_open_connection_state *state;
463 :
464 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
465 0 : state = tevent_req_data(req, struct roh_open_connection_state);
466 :
467 0 : status = roh_send_RPC_DATA_OUT_recv(subreq);
468 0 : TALLOC_FREE(subreq);
469 0 : if (tevent_req_nterror(req, status)) {
470 0 : return;
471 : }
472 :
473 0 : subreq = roh_send_CONN_A1_send(state, state->event_ctx, state->roh);
474 0 : if (tevent_req_nomem(subreq, req)) {
475 0 : return;
476 : }
477 0 : tevent_req_set_callback(subreq, roh_send_CONN_A1_done, req);
478 : }
479 :
480 : static void roh_send_CONN_B1_done(struct tevent_req *);
481 0 : static void roh_send_CONN_A1_done(struct tevent_req *subreq)
482 : {
483 0 : NTSTATUS status;
484 0 : struct tevent_req *req;
485 0 : struct roh_open_connection_state *state;
486 :
487 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
488 0 : state = tevent_req_data(req, struct roh_open_connection_state);
489 :
490 0 : status = roh_send_CONN_A1_recv(subreq);
491 0 : TALLOC_FREE(subreq);
492 0 : if (tevent_req_nterror(req, status)) {
493 0 : return;
494 : }
495 :
496 0 : subreq = roh_send_CONN_B1_send(state, state->event_ctx, state->roh);
497 0 : if (tevent_req_nomem(subreq, req)) {
498 0 : return;
499 : }
500 0 : tevent_req_set_callback(subreq, roh_send_CONN_B1_done, req);
501 : }
502 :
503 : static void roh_recv_out_channel_response_done(struct tevent_req *);
504 0 : static void roh_send_CONN_B1_done(struct tevent_req *subreq)
505 : {
506 0 : NTSTATUS status;
507 0 : struct tevent_req *req;
508 0 : struct roh_open_connection_state *state;
509 :
510 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
511 0 : state = tevent_req_data(req, struct roh_open_connection_state);
512 :
513 0 : status = roh_send_CONN_B1_recv(subreq);
514 0 : TALLOC_FREE(subreq);
515 0 : if (tevent_req_nterror(req, status)) {
516 0 : return;
517 : }
518 :
519 0 : state->roh->connection_state = ROH_STATE_OUT_CHANNEL_WAIT;
520 0 : subreq = roh_recv_out_channel_response_send(state, state->event_ctx,
521 : state->roh);
522 0 : if (tevent_req_nomem(subreq, req)) {
523 0 : return;
524 : }
525 0 : tevent_req_set_callback(subreq, roh_recv_out_channel_response_done, req);
526 : }
527 :
528 : static void roh_recv_CONN_A3_done(struct tevent_req *);
529 0 : static void roh_recv_out_channel_response_done(struct tevent_req *subreq)
530 : {
531 0 : NTSTATUS status;
532 0 : char *response;
533 0 : struct tevent_req *req;
534 0 : struct roh_open_connection_state *state;
535 :
536 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
537 0 : state = tevent_req_data(req, struct roh_open_connection_state);
538 :
539 0 : status = roh_recv_out_channel_response_recv(subreq, state, &response);
540 0 : TALLOC_FREE(subreq);
541 0 : if (tevent_req_nterror(req, status)) {
542 0 : return;
543 : }
544 :
545 0 : state->roh->connection_state = ROH_STATE_WAIT_A3W;
546 0 : subreq = roh_recv_CONN_A3_send(state, state->event_ctx, state->roh);
547 0 : if (tevent_req_nomem(subreq, req)) {
548 0 : return;
549 : }
550 0 : tevent_req_set_callback(subreq, roh_recv_CONN_A3_done, req);
551 : }
552 :
553 : static void roh_recv_CONN_C2_done(struct tevent_req *);
554 0 : static void roh_recv_CONN_A3_done(struct tevent_req *subreq)
555 : {
556 0 : NTSTATUS status;
557 0 : struct tevent_req *req;
558 0 : struct roh_open_connection_state *state;
559 :
560 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
561 0 : state = tevent_req_data(req, struct roh_open_connection_state);
562 :
563 0 : status = roh_recv_CONN_A3_recv(subreq, &state->roh->default_channel_out->connection_timeout);
564 0 : TALLOC_FREE(subreq);
565 0 : if (tevent_req_nterror(req, status)) {
566 0 : return;
567 : }
568 :
569 0 : state->roh->connection_state = ROH_STATE_WAIT_C2;
570 0 : subreq = roh_recv_CONN_C2_send(state, state->event_ctx, state->roh);
571 0 : if (tevent_req_nomem(subreq, req)) {
572 0 : return;
573 : }
574 0 : tevent_req_set_callback(subreq, roh_recv_CONN_C2_done, req);
575 : }
576 :
577 0 : static void roh_recv_CONN_C2_done(struct tevent_req *subreq)
578 : {
579 0 : NTSTATUS status;
580 0 : struct tevent_req *req;
581 0 : struct roh_open_connection_state *state;
582 0 : unsigned int version;
583 0 : unsigned int recv;
584 0 : unsigned int timeout;
585 :
586 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
587 0 : state = tevent_req_data(req, struct roh_open_connection_state);
588 :
589 0 : status = roh_recv_CONN_C2_recv(subreq, &version, &recv, &timeout);
590 0 : TALLOC_FREE(subreq);
591 0 : if (tevent_req_nterror(req, status)) {
592 0 : return;
593 : }
594 0 : state->roh->connection_state = ROH_STATE_OPENED;
595 :
596 0 : tevent_req_done(req);
597 : }
598 :
599 0 : static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream)
600 : {
601 0 : struct tstream_roh_context *ctx = NULL;
602 0 : struct tstream_context *tstream = NULL;
603 :
604 0 : ctx = tstream_context_data(stream, struct tstream_roh_context);
605 0 : if (!ctx->roh_conn) {
606 0 : errno = ENOTCONN;
607 0 : return -1;
608 : }
609 :
610 0 : tstream = http_conn_tstream(
611 0 : ctx->roh_conn->default_channel_out->http_conn);
612 0 : if (tstream == NULL) {
613 0 : errno = ENOTCONN;
614 0 : return -1;
615 : }
616 0 : return tstream_pending_bytes(tstream);
617 : }
618 :
619 : struct tstream_roh_readv_state {
620 : struct roh_connection *roh_conn;
621 : int ret;
622 : };
623 :
624 : static void tstream_roh_readv_handler(struct tevent_req *subreq);
625 0 : static struct tevent_req * tstream_roh_readv_send(TALLOC_CTX *mem_ctx,
626 : struct tevent_context *ev,
627 : struct tstream_context *stream,
628 : struct iovec *vector,
629 : size_t count)
630 : {
631 0 : struct tstream_roh_context *ctx = NULL;
632 0 : struct tstream_roh_readv_state *state;
633 0 : struct tevent_req *req, *subreq;
634 0 : struct tstream_context *channel_stream = NULL;
635 :
636 0 : req = tevent_req_create(mem_ctx, &state, struct tstream_roh_readv_state);
637 0 : if (!req) {
638 0 : return NULL;
639 : }
640 :
641 0 : ctx = tstream_context_data(stream, struct tstream_roh_context);
642 0 : if (!ctx->roh_conn) {
643 0 : tevent_req_error(req, ENOTCONN);
644 0 : goto post;
645 : }
646 0 : if (!ctx->roh_conn->default_channel_out) {
647 0 : tevent_req_error(req, ENOTCONN);
648 0 : goto post;
649 : }
650 0 : channel_stream = http_conn_tstream(
651 0 : ctx->roh_conn->default_channel_out->http_conn);
652 0 : if (channel_stream == NULL) {
653 0 : tevent_req_error(req, ENOTCONN);
654 0 : goto post;
655 : }
656 :
657 0 : state->roh_conn = ctx->roh_conn;
658 :
659 0 : subreq = tstream_readv_send(state, ev,
660 : channel_stream,
661 : vector, count);
662 0 : if (tevent_req_nomem(subreq, req)) {
663 0 : goto post;
664 : }
665 0 : tevent_req_set_callback(subreq, tstream_roh_readv_handler, req);
666 :
667 0 : return req;
668 0 : post:
669 0 : tevent_req_post(req, ev);
670 0 : return req;
671 : }
672 :
673 0 : static void tstream_roh_readv_handler(struct tevent_req *subreq)
674 : {
675 0 : struct tevent_req *req;
676 0 : struct tstream_roh_readv_state *state;
677 0 : int ret;
678 0 : int sys_errno;
679 :
680 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
681 0 : state = tevent_req_data(req, struct tstream_roh_readv_state);
682 0 : ret = tstream_readv_recv(subreq, &sys_errno);
683 0 : TALLOC_FREE(subreq);
684 0 : if (ret == -1) {
685 0 : tevent_req_error(req, sys_errno);
686 0 : return;
687 : }
688 :
689 0 : state->ret = ret;
690 :
691 0 : tevent_req_done(req);
692 : }
693 :
694 0 : static int tstream_roh_readv_recv(struct tevent_req *req, int *perrno)
695 : {
696 0 : struct tstream_roh_readv_state *state;
697 0 : int ret;
698 :
699 0 : state = tevent_req_data(req, struct tstream_roh_readv_state);
700 0 : ret = tsocket_simple_int_recv(req, perrno);
701 0 : if (ret == 0) {
702 0 : ret = state->ret;
703 : }
704 :
705 0 : tevent_req_received(req);
706 0 : return ret;
707 : }
708 :
709 : struct tstream_roh_writev_state {
710 : struct roh_connection *roh_conn;
711 : int nwritten;
712 : };
713 :
714 : static void tstream_roh_writev_handler(struct tevent_req *subreq);
715 0 : static struct tevent_req * tstream_roh_writev_send(TALLOC_CTX *mem_ctx,
716 : struct tevent_context *ev,
717 : struct tstream_context *stream,
718 : const struct iovec *vector,
719 : size_t count)
720 : {
721 0 : struct tstream_roh_context *ctx = NULL;
722 0 : struct tstream_roh_writev_state *state = NULL;
723 0 : struct tevent_req *req = NULL;
724 0 : struct tevent_req *subreq = NULL;
725 0 : struct tstream_context *channel_stream = NULL;
726 :
727 0 : req = tevent_req_create(mem_ctx, &state,
728 : struct tstream_roh_writev_state);
729 0 : if (!req) {
730 0 : return NULL;
731 : }
732 :
733 0 : ctx = tstream_context_data(stream, struct tstream_roh_context);
734 0 : if (!ctx->roh_conn) {
735 0 : tevent_req_error(req, ENOTCONN);
736 0 : goto post;
737 : }
738 0 : if (!ctx->roh_conn->default_channel_in) {
739 0 : tevent_req_error(req, ENOTCONN);
740 0 : goto post;
741 : }
742 0 : channel_stream = http_conn_tstream(
743 0 : ctx->roh_conn->default_channel_in->http_conn);
744 0 : if (channel_stream == NULL) {
745 0 : tevent_req_error(req, ENOTCONN);
746 0 : goto post;
747 : }
748 :
749 0 : state->roh_conn = ctx->roh_conn;
750 :
751 0 : subreq = tstream_writev_send(state, ev,
752 : channel_stream,
753 : vector, count);
754 0 : if (tevent_req_nomem(subreq, req)) {
755 0 : goto post;
756 : }
757 0 : tevent_req_set_callback(subreq, tstream_roh_writev_handler, req);
758 :
759 0 : return req;
760 0 : post:
761 0 : tevent_req_post(req, ev);
762 0 : return req;
763 : }
764 :
765 0 : static void tstream_roh_writev_handler(struct tevent_req *subreq)
766 : {
767 0 : struct tevent_req *req;
768 0 : struct tstream_roh_writev_state *state;
769 0 : int nwritten;
770 0 : int sys_errno;
771 :
772 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
773 0 : state = tevent_req_data(req, struct tstream_roh_writev_state);
774 0 : nwritten = tstream_writev_recv(subreq, &sys_errno);
775 0 : TALLOC_FREE(subreq);
776 0 : if (nwritten == -1) {
777 0 : tevent_req_error(req, sys_errno);
778 0 : return;
779 : }
780 0 : state->nwritten = nwritten;
781 0 : state->roh_conn->default_channel_in->sent_bytes += nwritten;
782 :
783 0 : tevent_req_done(req);
784 : }
785 :
786 0 : static int tstream_roh_writev_recv(struct tevent_req *req, int *perrno)
787 : {
788 0 : struct tstream_roh_writev_state *state;
789 0 : int ret;
790 :
791 0 : state = tevent_req_data(req, struct tstream_roh_writev_state);
792 0 : ret = tsocket_simple_int_recv(req, perrno);
793 0 : if (ret == 0) {
794 0 : ret = state->nwritten;
795 : }
796 :
797 0 : return ret;
798 : }
799 :
800 : struct tstream_roh_disconnect_state {
801 : struct tstream_context *stream;
802 : struct tevent_context *ev;
803 : };
804 :
805 : static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq);
806 0 : static struct tevent_req * tstream_roh_disconnect_send(TALLOC_CTX *mem_ctx,
807 : struct tevent_context *ev,
808 : struct tstream_context *stream)
809 : {
810 0 : struct tstream_roh_context *ctx = NULL;
811 0 : struct tevent_req *req, *subreq;
812 0 : struct tstream_roh_disconnect_state *state;
813 :
814 0 : req = tevent_req_create(mem_ctx, &state, struct tstream_roh_disconnect_state);
815 0 : if (req == NULL) {
816 0 : return NULL;
817 : }
818 :
819 0 : state->stream = stream;
820 0 : state->ev = ev;
821 :
822 0 : ctx = tstream_context_data(stream, struct tstream_roh_context);
823 0 : if (!ctx->roh_conn) {
824 0 : tevent_req_error(req, ENOTCONN);
825 0 : goto post;
826 : }
827 0 : if (!ctx->roh_conn->default_channel_in) {
828 0 : tevent_req_error(req, ENOTCONN);
829 0 : goto post;
830 : }
831 :
832 0 : subreq = http_disconnect_send(
833 : state,
834 : ev,
835 0 : ctx->roh_conn->default_channel_in->http_conn);
836 0 : if (tevent_req_nomem(subreq, req)) {
837 0 : goto post;
838 : }
839 0 : tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_in_handler, req);
840 :
841 0 : return req;
842 0 : post:
843 0 : tevent_req_post(req, ev);
844 0 : return req;
845 : }
846 :
847 : static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq);
848 :
849 0 : static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq)
850 : {
851 0 : struct tevent_req *req;
852 0 : struct tstream_roh_disconnect_state *state;
853 0 : struct tstream_context *stream;
854 0 : struct tstream_roh_context *roh_stream;
855 0 : int ret;
856 :
857 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
858 0 : state = tevent_req_data(req, struct tstream_roh_disconnect_state);
859 0 : stream = state->stream;
860 0 : roh_stream = tstream_context_data(stream, struct tstream_roh_context);
861 :
862 0 : ret = http_disconnect_recv(subreq);
863 0 : TALLOC_FREE(subreq);
864 0 : if (ret != 0) {
865 0 : tevent_req_error(req, ret);
866 0 : return;
867 : }
868 0 : TALLOC_FREE(roh_stream->roh_conn->default_channel_in);
869 :
870 0 : subreq = http_disconnect_send(
871 : state,
872 : state->ev,
873 0 : roh_stream->roh_conn->default_channel_out->http_conn);
874 0 : if (tevent_req_nomem(subreq, req)) {
875 0 : return;
876 : }
877 0 : tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_out_handler, req);
878 :
879 0 : return;
880 : }
881 :
882 0 : static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq)
883 : {
884 0 : struct tevent_req *req;
885 0 : struct tstream_roh_disconnect_state *state;
886 0 : struct tstream_context *stream;
887 0 : struct tstream_roh_context *roh_stream;
888 0 : int ret;
889 :
890 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
891 0 : state = tevent_req_data(req, struct tstream_roh_disconnect_state);
892 0 : stream = state->stream;
893 0 : roh_stream = tstream_context_data(stream, struct tstream_roh_context);
894 :
895 0 : ret = http_disconnect_recv(subreq);
896 0 : TALLOC_FREE(subreq);
897 0 : if (ret != 0) {
898 0 : tevent_req_error(req, ret);
899 0 : return;
900 : }
901 0 : TALLOC_FREE(roh_stream->roh_conn->default_channel_out);
902 :
903 0 : tevent_req_done(req);
904 : }
905 :
906 0 : static int tstream_roh_disconnect_recv(struct tevent_req *req, int *perrno)
907 : {
908 0 : int ret;
909 :
910 0 : ret = tsocket_simple_int_recv(req, perrno);
911 0 : tevent_req_received(req);
912 :
913 0 : return ret;
914 : }
|