s4-rpc_server: Do not use LM hash in password changes
[Samba.git] / source4 / librpc / rpc / dcerpc_roh.c
blob3aa7551034a1d2cb674d8613b642b902c32e7293
1 /*
2 Unix SMB/CIFS implementation.
4 [MS-RPCH] - RPC over HTTP client
6 Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
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.
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.
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/>.
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"
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);
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,
70 struct tstream_roh_context {
71 struct roh_connection *roh_conn;
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;
82 struct dcecli_connection *conn;
83 bool tls;
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;
91 struct roh_connection *roh;
92 struct tstream_tls_params *tls_params;
93 struct loadparm_context *lp_ctx;
94 uint8_t http_auth;
97 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)
102 struct roh_open_connection_state *state;
103 struct tstream_roh_context *roh_stream_ctx;
104 NTSTATUS status;
106 state = tevent_req_data(req, struct roh_open_connection_state);
107 if (tevent_req_is_nterror(req, &status)) {
108 tevent_req_received(req);
109 return status;
112 *stream = tstream_context_create(mem_ctx, &tstream_roh_ops,
113 &roh_stream_ctx,
114 struct tstream_roh_context,
115 __location__);
116 if (!stream) {
117 tevent_req_received(req);
118 return NT_STATUS_NO_MEMORY;
120 ZERO_STRUCTP(roh_stream_ctx);
122 roh_stream_ctx->roh_conn = talloc_move(mem_ctx, &state->roh);
123 *queue = http_conn_send_queue(
124 roh_stream_ctx->roh_conn->default_channel_in->http_conn);
126 tevent_req_received(req);
128 return NT_STATUS_OK;
131 struct roh_connect_channel_state {
132 struct roh_channel *channel;
135 static void roh_connect_channel_done(struct tevent_req *subreq);
136 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)
144 struct tevent_req *req = NULL;
145 struct tevent_req *subreq = NULL;
146 struct roh_connect_channel_state *state = NULL;
148 DBG_DEBUG("Connecting ROH channel socket, RPC proxy is "
149 "%s:%d (TLS: %s)\n", rpcproxy_ip_address, rpcproxy_port,
150 (tls ? "true" : "false"));
152 req = tevent_req_create(mem_ctx, &state,
153 struct roh_connect_channel_state);
154 if (req == NULL) {
155 return NULL;
158 if (!is_ipaddress(rpcproxy_ip_address)) {
159 DBG_ERR("Invalid host (%s), needs to be an IP address\n",
160 rpcproxy_ip_address);
161 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
162 return tevent_req_post(req, ev);
165 /* Initialize channel structure */
166 state->channel = talloc_zero(state, struct roh_channel);
167 if (tevent_req_nomem(state->channel, req)) {
168 return tevent_req_post(req, ev);
171 state->channel->channel_cookie = GUID_random();
173 subreq = http_connect_send(state,
175 rpcproxy_ip_address,
176 rpcproxy_port,
177 credentials,
178 tls ? tls_params : NULL);
179 if (tevent_req_nomem(subreq, req)) {
180 return tevent_req_post(req, ev);
182 tevent_req_set_callback(subreq, roh_connect_channel_done, req);
184 return req;
187 static void roh_connect_channel_done(struct tevent_req *subreq)
189 struct tevent_req *req = NULL;
190 struct roh_connect_channel_state *state = NULL;
191 NTSTATUS status;
192 int ret;
194 req = tevent_req_callback_data(subreq, struct tevent_req);
195 state = tevent_req_data(req, struct roh_connect_channel_state);
197 ret = http_connect_recv(subreq,
198 state->channel,
199 &state->channel->http_conn);
200 TALLOC_FREE(subreq);
201 if (ret != 0) {
202 status = map_nt_error_from_unix_common(ret);
203 tevent_req_nterror(req, status);
204 return;
207 DBG_DEBUG("HTTP connected\n");
208 tevent_req_done(req);
211 static NTSTATUS roh_connect_channel_recv(struct tevent_req *req,
212 TALLOC_CTX *mem_ctx,
213 struct roh_channel **channel)
215 struct roh_connect_channel_state *state = tevent_req_data(
216 req, struct roh_connect_channel_state);
217 NTSTATUS status;
219 if (tevent_req_is_nterror(req, &status)) {
220 tevent_req_received(req);
221 return status;
224 *channel = talloc_move(mem_ctx, &state->channel);
225 tevent_req_received(req);
227 return NT_STATUS_OK;
230 static void roh_continue_resolve_name(struct composite_context *ctx);
233 * Send rpc pipe open request to given host:port using http transport
235 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)
250 NTSTATUS status;
251 struct tevent_req *req;
252 struct composite_context *ctx;
253 struct roh_open_connection_state *state;
254 struct nbt_name name;
256 req = tevent_req_create(conn, &state, struct roh_open_connection_state);
257 if (req == NULL) {
258 return NULL;
261 /* Set state fields */
262 state->req = req;
263 state->event_ctx = conn->event_ctx;
264 state->lp_ctx = lp_ctx,
265 state->credentials = credentials;
266 state->conn = conn;
267 state->tls = use_tls;
269 /* Initialize connection structure (3.2.1.3) */
270 /* TODO Initialize virtual connection cookie table */
271 state->rpc_server = talloc_strdup(state, rpc_server);
272 state->rpc_server_port = rpc_server_port;
273 state->rpc_proxy = talloc_strdup(state, rpc_proxy);
274 state->rpc_proxy_port = rpc_proxy_port;
275 state->http_auth = http_auth;
277 state->roh = talloc_zero(state, struct roh_connection);
278 state->roh->protocol_version = ROH_V2;
279 state->roh->connection_state = ROH_STATE_OPEN_START;
280 state->roh->connection_cookie = GUID_random();
281 state->roh->association_group_id_cookie = GUID_random();
283 /* Additional initialization steps (3.2.2.3) */
284 state->roh->proxy_use = use_proxy;
285 state->roh->current_keep_alive_time = 0;
286 state->roh->current_keep_alive_interval = 0;
288 /* Initialize TLS */
289 if (use_tls) {
290 char *ca_file = lpcfg_tls_cafile(state, lp_ctx);
291 char *crl_file = lpcfg_tls_crlfile(state, lp_ctx);
292 const char *tls_priority = lpcfg_tls_priority(lp_ctx);
293 enum tls_verify_peer_state verify_peer =
294 lpcfg_tls_verify_peer(lp_ctx);
296 status = tstream_tls_params_client(state->roh,
297 ca_file, crl_file,
298 tls_priority,
299 verify_peer,
300 state->rpc_proxy,
301 &state->tls_params);
302 if (!NT_STATUS_IS_OK(status)) {
303 DEBUG(0,("%s: Failed tstream_tls_params_client - %s\n",
304 __func__, nt_errstr(status)));
305 tevent_req_nterror(req, status);
306 return tevent_req_post(req, conn->event_ctx);
310 /* Resolve RPC proxy server name */
311 make_nbt_name_server(&name, state->rpc_proxy);
312 ctx = resolve_name_send(resolve_ctx, state, &name, state->event_ctx);
313 if (tevent_req_nomem(ctx, req)) {
314 return tevent_req_post(req, state->event_ctx);
316 ctx->async.fn = roh_continue_resolve_name;
317 ctx->async.private_data = state;
319 return req;
322 static void roh_connect_channel_in_done(struct tevent_req *subreq);
323 static void roh_continue_resolve_name(struct composite_context *ctx)
325 NTSTATUS status;
326 struct roh_open_connection_state *state;
327 struct tevent_req *subreq;
329 state = talloc_get_type_abort(ctx->async.private_data,
330 struct roh_open_connection_state);
331 status = resolve_name_multiple_recv(ctx, state,
332 &state->rpcproxy_addresses);
333 if (tevent_req_nterror(state->req, status)) {
334 DEBUG(2, ("%s: No server found: %s\n", __func__,
335 nt_errstr(status)));
336 return;
339 state->rpcproxy_address_index = 0;
340 if (state->rpcproxy_addresses[state->rpcproxy_address_index] == NULL) {
341 DEBUG(2, ("%s: No server found\n", __func__));
342 tevent_req_nterror(state->req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
343 return;
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
351 state->roh->connection_state = ROH_STATE_OPEN_START;
352 subreq = roh_connect_channel_send(state,
353 state->event_ctx,
354 state->rpcproxy_addresses[state->rpcproxy_address_index],
355 state->rpc_proxy_port,
356 state->credentials,
357 state->tls,
358 state->tls_params);
359 if (tevent_req_nomem(subreq, state->req)) {
360 return;
362 tevent_req_set_callback(subreq, roh_connect_channel_in_done, state->req);
365 static void roh_connect_channel_out_done(struct tevent_req *);
366 static void roh_connect_channel_in_done(struct tevent_req *subreq)
368 NTSTATUS status;
369 struct tevent_req *req;
370 struct roh_open_connection_state *state;
372 req = tevent_req_callback_data(subreq, struct tevent_req);
373 state = tevent_req_data(req, struct roh_open_connection_state);
375 status = roh_connect_channel_recv(subreq, state->roh,
376 &state->roh->default_channel_in);
377 TALLOC_FREE(subreq);
378 if (tevent_req_nterror(req, status)) {
379 return;
382 subreq = roh_connect_channel_send(state,
383 state->event_ctx,
384 state->rpcproxy_addresses[state->rpcproxy_address_index],
385 state->rpc_proxy_port,
386 state->credentials,
387 state->tls,
388 state->tls_params);
389 if (tevent_req_nomem(subreq, req)) {
390 return;
392 tevent_req_set_callback(subreq, roh_connect_channel_out_done, req);
395 static void roh_send_RPC_DATA_IN_done(struct tevent_req *);
396 static void roh_connect_channel_out_done(struct tevent_req *subreq)
398 NTSTATUS status;
399 struct tevent_req *req;
400 struct roh_open_connection_state *state;
402 req = tevent_req_callback_data(subreq, struct tevent_req);
403 state = tevent_req_data(req, struct roh_open_connection_state);
405 status = roh_connect_channel_recv(subreq, state->roh,
406 &state->roh->default_channel_out);
407 TALLOC_FREE(subreq);
408 if (tevent_req_nterror(req, status)) {
409 return;
412 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 state->http_auth);
420 if (tevent_req_nomem(subreq, req)) {
421 return;
423 tevent_req_set_callback(subreq, roh_send_RPC_DATA_IN_done, req);
426 static void roh_send_RPC_DATA_OUT_done(struct tevent_req *);
427 static void roh_send_RPC_DATA_IN_done(struct tevent_req *subreq)
429 NTSTATUS status;
430 struct tevent_req *req;
431 struct roh_open_connection_state *state;
433 req = tevent_req_callback_data(subreq, struct tevent_req);
434 state = tevent_req_data(req, struct roh_open_connection_state);
436 status = roh_send_RPC_DATA_IN_recv(subreq);
437 TALLOC_FREE(subreq);
438 if (tevent_req_nterror(req, status)) {
439 return;
442 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 state->http_auth);
451 if (tevent_req_nomem(subreq, req)) {
452 return;
454 tevent_req_set_callback(subreq, roh_send_RPC_DATA_OUT_done, req);
457 static void roh_send_CONN_A1_done(struct tevent_req *);
458 static void roh_send_RPC_DATA_OUT_done(struct tevent_req *subreq)
460 NTSTATUS status;
461 struct tevent_req *req;
462 struct roh_open_connection_state *state;
464 req = tevent_req_callback_data(subreq, struct tevent_req);
465 state = tevent_req_data(req, struct roh_open_connection_state);
467 status = roh_send_RPC_DATA_OUT_recv(subreq);
468 TALLOC_FREE(subreq);
469 if (tevent_req_nterror(req, status)) {
470 return;
473 subreq = roh_send_CONN_A1_send(state, state->event_ctx, state->roh);
474 if (tevent_req_nomem(subreq, req)) {
475 return;
477 tevent_req_set_callback(subreq, roh_send_CONN_A1_done, req);
480 static void roh_send_CONN_B1_done(struct tevent_req *);
481 static void roh_send_CONN_A1_done(struct tevent_req *subreq)
483 NTSTATUS status;
484 struct tevent_req *req;
485 struct roh_open_connection_state *state;
487 req = tevent_req_callback_data(subreq, struct tevent_req);
488 state = tevent_req_data(req, struct roh_open_connection_state);
490 status = roh_send_CONN_A1_recv(subreq);
491 TALLOC_FREE(subreq);
492 if (tevent_req_nterror(req, status)) {
493 return;
496 subreq = roh_send_CONN_B1_send(state, state->event_ctx, state->roh);
497 if (tevent_req_nomem(subreq, req)) {
498 return;
500 tevent_req_set_callback(subreq, roh_send_CONN_B1_done, req);
503 static void roh_recv_out_channel_response_done(struct tevent_req *);
504 static void roh_send_CONN_B1_done(struct tevent_req *subreq)
506 NTSTATUS status;
507 struct tevent_req *req;
508 struct roh_open_connection_state *state;
510 req = tevent_req_callback_data(subreq, struct tevent_req);
511 state = tevent_req_data(req, struct roh_open_connection_state);
513 status = roh_send_CONN_B1_recv(subreq);
514 TALLOC_FREE(subreq);
515 if (tevent_req_nterror(req, status)) {
516 return;
519 state->roh->connection_state = ROH_STATE_OUT_CHANNEL_WAIT;
520 subreq = roh_recv_out_channel_response_send(state, state->event_ctx,
521 state->roh);
522 if (tevent_req_nomem(subreq, req)) {
523 return;
525 tevent_req_set_callback(subreq, roh_recv_out_channel_response_done, req);
528 static void roh_recv_CONN_A3_done(struct tevent_req *);
529 static void roh_recv_out_channel_response_done(struct tevent_req *subreq)
531 NTSTATUS status;
532 char *response;
533 struct tevent_req *req;
534 struct roh_open_connection_state *state;
536 req = tevent_req_callback_data(subreq, struct tevent_req);
537 state = tevent_req_data(req, struct roh_open_connection_state);
539 status = roh_recv_out_channel_response_recv(subreq, state, &response);
540 TALLOC_FREE(subreq);
541 if (tevent_req_nterror(req, status)) {
542 return;
545 state->roh->connection_state = ROH_STATE_WAIT_A3W;
546 subreq = roh_recv_CONN_A3_send(state, state->event_ctx, state->roh);
547 if (tevent_req_nomem(subreq, req)) {
548 return;
550 tevent_req_set_callback(subreq, roh_recv_CONN_A3_done, req);
553 static void roh_recv_CONN_C2_done(struct tevent_req *);
554 static void roh_recv_CONN_A3_done(struct tevent_req *subreq)
556 NTSTATUS status;
557 struct tevent_req *req;
558 struct roh_open_connection_state *state;
560 req = tevent_req_callback_data(subreq, struct tevent_req);
561 state = tevent_req_data(req, struct roh_open_connection_state);
563 status = roh_recv_CONN_A3_recv(subreq, &state->roh->default_channel_out->connection_timeout);
564 TALLOC_FREE(subreq);
565 if (tevent_req_nterror(req, status)) {
566 return;
569 state->roh->connection_state = ROH_STATE_WAIT_C2;
570 subreq = roh_recv_CONN_C2_send(state, state->event_ctx, state->roh);
571 if (tevent_req_nomem(subreq, req)) {
572 return;
574 tevent_req_set_callback(subreq, roh_recv_CONN_C2_done, req);
577 static void roh_recv_CONN_C2_done(struct tevent_req *subreq)
579 NTSTATUS status;
580 struct tevent_req *req;
581 struct roh_open_connection_state *state;
582 unsigned int version;
583 unsigned int recv;
584 unsigned int timeout;
586 req = tevent_req_callback_data(subreq, struct tevent_req);
587 state = tevent_req_data(req, struct roh_open_connection_state);
589 status = roh_recv_CONN_C2_recv(subreq, &version, &recv, &timeout);
590 TALLOC_FREE(subreq);
591 if (tevent_req_nterror(req, status)) {
592 return;
594 state->roh->connection_state = ROH_STATE_OPENED;
596 tevent_req_done(req);
599 static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream)
601 struct tstream_roh_context *ctx = NULL;
602 struct tstream_context *tstream = NULL;
604 ctx = tstream_context_data(stream, struct tstream_roh_context);
605 if (!ctx->roh_conn) {
606 errno = ENOTCONN;
607 return -1;
610 tstream = http_conn_tstream(
611 ctx->roh_conn->default_channel_out->http_conn);
612 if (tstream == NULL) {
613 errno = ENOTCONN;
614 return -1;
616 return tstream_pending_bytes(tstream);
619 struct tstream_roh_readv_state {
620 struct roh_connection *roh_conn;
621 int ret;
624 static void tstream_roh_readv_handler(struct tevent_req *subreq);
625 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)
631 struct tstream_roh_context *ctx = NULL;
632 struct tstream_roh_readv_state *state;
633 struct tevent_req *req, *subreq;
634 struct tstream_context *channel_stream = NULL;
636 req = tevent_req_create(mem_ctx, &state, struct tstream_roh_readv_state);
637 if (!req) {
638 return NULL;
641 ctx = tstream_context_data(stream, struct tstream_roh_context);
642 if (!ctx->roh_conn) {
643 tevent_req_error(req, ENOTCONN);
644 goto post;
646 if (!ctx->roh_conn->default_channel_out) {
647 tevent_req_error(req, ENOTCONN);
648 goto post;
650 channel_stream = http_conn_tstream(
651 ctx->roh_conn->default_channel_out->http_conn);
652 if (channel_stream == NULL) {
653 tevent_req_error(req, ENOTCONN);
654 goto post;
657 state->roh_conn = ctx->roh_conn;
659 subreq = tstream_readv_send(state, ev,
660 channel_stream,
661 vector, count);
662 if (tevent_req_nomem(subreq, req)) {
663 goto post;
665 tevent_req_set_callback(subreq, tstream_roh_readv_handler, req);
667 return req;
668 post:
669 tevent_req_post(req, ev);
670 return req;
673 static void tstream_roh_readv_handler(struct tevent_req *subreq)
675 struct tevent_req *req;
676 struct tstream_roh_readv_state *state;
677 int ret;
678 int sys_errno;
680 req = tevent_req_callback_data(subreq, struct tevent_req);
681 state = tevent_req_data(req, struct tstream_roh_readv_state);
682 ret = tstream_readv_recv(subreq, &sys_errno);
683 TALLOC_FREE(subreq);
684 if (ret == -1) {
685 tevent_req_error(req, sys_errno);
686 return;
689 state->ret = ret;
691 tevent_req_done(req);
694 static int tstream_roh_readv_recv(struct tevent_req *req, int *perrno)
696 struct tstream_roh_readv_state *state;
697 int ret;
699 state = tevent_req_data(req, struct tstream_roh_readv_state);
700 ret = tsocket_simple_int_recv(req, perrno);
701 if (ret == 0) {
702 ret = state->ret;
705 tevent_req_received(req);
706 return ret;
709 struct tstream_roh_writev_state {
710 struct roh_connection *roh_conn;
711 int nwritten;
714 static void tstream_roh_writev_handler(struct tevent_req *subreq);
715 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)
721 struct tstream_roh_context *ctx = NULL;
722 struct tstream_roh_writev_state *state = NULL;
723 struct tevent_req *req = NULL;
724 struct tevent_req *subreq = NULL;
725 struct tstream_context *channel_stream = NULL;
727 req = tevent_req_create(mem_ctx, &state,
728 struct tstream_roh_writev_state);
729 if (!req) {
730 return NULL;
733 ctx = tstream_context_data(stream, struct tstream_roh_context);
734 if (!ctx->roh_conn) {
735 tevent_req_error(req, ENOTCONN);
736 goto post;
738 if (!ctx->roh_conn->default_channel_in) {
739 tevent_req_error(req, ENOTCONN);
740 goto post;
742 channel_stream = http_conn_tstream(
743 ctx->roh_conn->default_channel_in->http_conn);
744 if (channel_stream == NULL) {
745 tevent_req_error(req, ENOTCONN);
746 goto post;
749 state->roh_conn = ctx->roh_conn;
751 subreq = tstream_writev_send(state, ev,
752 channel_stream,
753 vector, count);
754 if (tevent_req_nomem(subreq, req)) {
755 goto post;
757 tevent_req_set_callback(subreq, tstream_roh_writev_handler, req);
759 return req;
760 post:
761 tevent_req_post(req, ev);
762 return req;
765 static void tstream_roh_writev_handler(struct tevent_req *subreq)
767 struct tevent_req *req;
768 struct tstream_roh_writev_state *state;
769 int nwritten;
770 int sys_errno;
772 req = tevent_req_callback_data(subreq, struct tevent_req);
773 state = tevent_req_data(req, struct tstream_roh_writev_state);
774 nwritten = tstream_writev_recv(subreq, &sys_errno);
775 TALLOC_FREE(subreq);
776 if (nwritten == -1) {
777 tevent_req_error(req, sys_errno);
778 return;
780 state->nwritten = nwritten;
781 state->roh_conn->default_channel_in->sent_bytes += nwritten;
783 tevent_req_done(req);
786 static int tstream_roh_writev_recv(struct tevent_req *req, int *perrno)
788 struct tstream_roh_writev_state *state;
789 int ret;
791 state = tevent_req_data(req, struct tstream_roh_writev_state);
792 ret = tsocket_simple_int_recv(req, perrno);
793 if (ret == 0) {
794 ret = state->nwritten;
797 return ret;
800 struct tstream_roh_disconnect_state {
801 struct tstream_context *stream;
802 struct tevent_context *ev;
805 static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq);
806 static struct tevent_req * tstream_roh_disconnect_send(TALLOC_CTX *mem_ctx,
807 struct tevent_context *ev,
808 struct tstream_context *stream)
810 struct tstream_roh_context *ctx = NULL;
811 struct tevent_req *req, *subreq;
812 struct tstream_roh_disconnect_state *state;
814 req = tevent_req_create(mem_ctx, &state, struct tstream_roh_disconnect_state);
815 if (req == NULL) {
816 return NULL;
819 state->stream = stream;
820 state->ev = ev;
822 ctx = tstream_context_data(stream, struct tstream_roh_context);
823 if (!ctx->roh_conn) {
824 tevent_req_error(req, ENOTCONN);
825 goto post;
827 if (!ctx->roh_conn->default_channel_in) {
828 tevent_req_error(req, ENOTCONN);
829 goto post;
832 subreq = http_disconnect_send(
833 state,
835 ctx->roh_conn->default_channel_in->http_conn);
836 if (tevent_req_nomem(subreq, req)) {
837 goto post;
839 tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_in_handler, req);
841 return req;
842 post:
843 tevent_req_post(req, ev);
844 return req;
847 static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq);
849 static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq)
851 struct tevent_req *req;
852 struct tstream_roh_disconnect_state *state;
853 struct tstream_context *stream;
854 struct tstream_roh_context *roh_stream;
855 int ret;
857 req = tevent_req_callback_data(subreq, struct tevent_req);
858 state = tevent_req_data(req, struct tstream_roh_disconnect_state);
859 stream = state->stream;
860 roh_stream = tstream_context_data(stream, struct tstream_roh_context);
862 ret = http_disconnect_recv(subreq);
863 TALLOC_FREE(subreq);
864 if (ret != 0) {
865 tevent_req_error(req, ret);
866 return;
868 TALLOC_FREE(roh_stream->roh_conn->default_channel_in);
870 subreq = http_disconnect_send(
871 state,
872 state->ev,
873 roh_stream->roh_conn->default_channel_out->http_conn);
874 if (tevent_req_nomem(subreq, req)) {
875 return;
877 tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_out_handler, req);
879 return;
882 static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq)
884 struct tevent_req *req;
885 struct tstream_roh_disconnect_state *state;
886 struct tstream_context *stream;
887 struct tstream_roh_context *roh_stream;
888 int ret;
890 req = tevent_req_callback_data(subreq, struct tevent_req);
891 state = tevent_req_data(req, struct tstream_roh_disconnect_state);
892 stream = state->stream;
893 roh_stream = tstream_context_data(stream, struct tstream_roh_context);
895 ret = http_disconnect_recv(subreq);
896 TALLOC_FREE(subreq);
897 if (ret != 0) {
898 tevent_req_error(req, ret);
899 return;
901 TALLOC_FREE(roh_stream->roh_conn->default_channel_out);
903 tevent_req_done(req);
906 static int tstream_roh_disconnect_recv(struct tevent_req *req, int *perrno)
908 int ret;
910 ret = tsocket_simple_int_recv(req, perrno);
911 tevent_req_received(req);
913 return ret;