CVE-2016-2113: s4:librpc/rpc: verify the rpc_proxy certificate and hostname if configured
[samba.git] / source4 / librpc / rpc / dcerpc_roh.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    [MS-RPCH] - RPC over HTTP client
5
6    Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
7
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
36 static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream);
37 static struct tevent_req * tstream_roh_readv_send(
38                 TALLOC_CTX *mem_ctx,
39                 struct tevent_context *ev,
40                 struct tstream_context *stream,
41                 struct iovec *vector,
42                 size_t count);
43 static int tstream_roh_readv_recv(struct tevent_req *req, int *perrno);
44 static struct tevent_req * tstream_roh_writev_send(
45                 TALLOC_CTX *mem_ctx,
46                 struct tevent_context *ev,
47                 struct tstream_context *stream,
48                 const struct iovec *vector,
49                 size_t count);
50 static int tstream_roh_writev_recv(struct tevent_req *req, int *perrno);
51 static struct tevent_req * tstream_roh_disconnect_send(
52                 TALLOC_CTX *mem_ctx,
53                 struct tevent_context *ev,
54                 struct tstream_context *stream);
55 static int tstream_roh_disconnect_recv(struct tevent_req *req, int *perrno);
56
57 static const struct tstream_context_ops tstream_roh_ops = {
58         .name                   = "roh",
59         .pending_bytes          = tstream_roh_pending_bytes,
60         .readv_send             = tstream_roh_readv_send,
61         .readv_recv             = tstream_roh_readv_recv,
62         .writev_send            = tstream_roh_writev_send,
63         .writev_recv            = tstream_roh_writev_recv,
64         .disconnect_send        = tstream_roh_disconnect_send,
65         .disconnect_recv        = tstream_roh_disconnect_recv,
66 };
67
68 struct tstream_roh_context {
69         struct roh_connection *roh_conn;
70 };
71
72 struct roh_open_connection_state {
73         struct tevent_req               *req;
74         struct tevent_context           *event_ctx;
75         struct cli_credentials          *credentials;
76         struct resolve_context          *resolve_ctx;
77         const char                      **rpcproxy_addresses;
78         unsigned int                    rpcproxy_address_index;
79
80         struct dcecli_connection        *conn;
81         bool                            tls;
82
83         const char                      *rpc_proxy;
84         unsigned int                    rpc_proxy_port;
85         const char                      *rpc_server;
86         unsigned int                    rpc_server_port;
87         const char                      *target_hostname;
88
89         struct roh_connection           *roh;
90         struct tstream_tls_params       *tls_params;
91         struct loadparm_context         *lp_ctx;
92         bool                            use_ntlm;
93 };
94
95 NTSTATUS dcerpc_pipe_open_roh_recv(struct tevent_req *req,
96                                    TALLOC_CTX *mem_ctx,
97                                    struct tstream_context **stream,
98                                    struct tevent_queue **queue)
99 {
100         struct roh_open_connection_state *state;
101         struct tstream_roh_context *roh_stream_ctx;
102         NTSTATUS status;
103
104         state = tevent_req_data(req, struct roh_open_connection_state);
105         if (tevent_req_is_nterror(req, &status)) {
106                 tevent_req_received(req);
107                 return status;
108         }
109
110         *stream = tstream_context_create(mem_ctx, &tstream_roh_ops,
111                                          &roh_stream_ctx,
112                                          struct tstream_roh_context,
113                                          __location__);
114         if (!stream) {
115                 tevent_req_received(req);
116                 return NT_STATUS_NO_MEMORY;
117         }
118         ZERO_STRUCTP(roh_stream_ctx);
119
120         roh_stream_ctx->roh_conn = talloc_move(mem_ctx, &state->roh);
121         *queue = roh_stream_ctx->roh_conn->default_channel_in->send_queue;
122
123         tevent_req_received(req);
124
125         return NT_STATUS_OK;
126 }
127
128 static void roh_continue_resolve_name(struct composite_context *ctx);
129
130 /**
131  * Send rpc pipe open request to given host:port using http transport
132  */
133 struct tevent_req *dcerpc_pipe_open_roh_send(struct dcecli_connection *conn,
134                                              const char *localaddr,
135                                              const char *rpc_server,
136                                              uint32_t rpc_server_port,
137                                              const char *rpc_proxy,
138                                              uint32_t rpc_proxy_port,
139                                              const char *http_proxy,
140                                              uint32_t http_proxy_port,
141                                              bool use_tls,
142                                              bool use_proxy,
143                                              struct cli_credentials *credentials,
144                                              struct resolve_context *resolve_ctx,
145                                              struct loadparm_context *lp_ctx,
146                                              bool use_ntlm)
147 {
148         NTSTATUS                                status;
149         struct tevent_req                       *req;
150         struct composite_context                *ctx;
151         struct roh_open_connection_state        *state;
152         struct nbt_name                         name;
153
154         req = tevent_req_create(conn, &state, struct roh_open_connection_state);
155         if (req == NULL) {
156                 return NULL;
157         }
158
159         /* Set state fields */
160         state->req = req;
161         state->event_ctx = conn->event_ctx;
162         state->lp_ctx = lp_ctx,
163         state->credentials = credentials;
164         state->conn = conn;
165         state->tls = use_tls;
166
167         /* Initialize connection structure (3.2.1.3) */
168         /* TODO Initialize virtual connection cookie table */
169         state->rpc_server = talloc_strdup(state, rpc_server);
170         state->rpc_server_port = rpc_server_port;
171         state->rpc_proxy = talloc_strdup(state, rpc_proxy);
172         state->rpc_proxy_port = rpc_proxy_port;
173         state->use_ntlm = use_ntlm;
174
175         state->roh = talloc_zero(state, struct roh_connection);
176         state->roh->protocol_version = ROH_V2;
177         state->roh->connection_state = ROH_STATE_OPEN_START;
178         state->roh->connection_cookie = GUID_random();
179         state->roh->association_group_id_cookie = GUID_random();
180
181         /* Additional initialization steps (3.2.2.3) */
182         state->roh->proxy_use = use_proxy;
183         state->roh->current_keep_alive_time = 0;
184         state->roh->current_keep_alive_interval = 0;
185
186         /* Initialize TLS */
187         if (use_tls) {
188                 char *ca_file = lpcfg_tls_cafile(state, lp_ctx);
189                 char *crl_file = lpcfg_tls_crlfile(state, lp_ctx);
190                 const char *tls_priority = lpcfg_tls_priority(lp_ctx);
191                 enum tls_verify_peer_state verify_peer =
192                         lpcfg_tls_verify_peer(lp_ctx);
193
194                 status = tstream_tls_params_client(state->roh,
195                                                    ca_file, crl_file,
196                                                    tls_priority,
197                                                    verify_peer,
198                                                    state->rpc_proxy,
199                                                    &state->tls_params);
200                 if (!NT_STATUS_IS_OK(status)) {
201                         DEBUG(0,("%s: Failed tstream_tls_params_client - %s\n",
202                                  __func__, nt_errstr(status)));
203                         tevent_req_nterror(req, status);
204                         return tevent_req_post(req, conn->event_ctx);
205                 }
206         }
207
208         /* Resolve RPC proxy server name */
209         make_nbt_name_server(&name, state->rpc_proxy);
210         ctx = resolve_name_send(resolve_ctx, state, &name, state->event_ctx);
211         if (tevent_req_nomem(ctx, req)) {
212                 return tevent_req_post(req, state->event_ctx);
213         }
214         ctx->async.fn = roh_continue_resolve_name;
215         ctx->async.private_data = state;
216
217         return req;
218 }
219
220 static void roh_connect_channel_in_done(struct tevent_req *subreq);
221 static void roh_continue_resolve_name(struct composite_context *ctx)
222 {
223         NTSTATUS                                status;
224         struct roh_open_connection_state        *state;
225         struct tevent_req                       *subreq;
226
227         state = talloc_get_type_abort(ctx->async.private_data,
228                                       struct roh_open_connection_state);
229         status = resolve_name_multiple_recv(ctx, state,
230                                             &state->rpcproxy_addresses);
231         if (tevent_req_nterror(state->req, status)) {
232                 DEBUG(2, ("%s: No server found: %s\n", __func__,
233                           nt_errstr(status)));
234                 return;
235         }
236
237         state->rpcproxy_address_index = 0;
238         if (state->rpcproxy_addresses[state->rpcproxy_address_index] == NULL) {
239                 DEBUG(2, ("%s: No server found\n", __func__));
240                 tevent_req_nterror(state->req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
241                 return;
242         }
243
244         /*
245          * TODO Determine proxy use
246          * If state->roh->proxy_use == true, the client has requested to
247          * always use local proxy. Otherwise, run the proxy use discovery
248          */
249         state->roh->connection_state = ROH_STATE_OPEN_START;
250         subreq = roh_connect_channel_in_send(state,
251                                              state->event_ctx,
252                                              state->rpcproxy_addresses[state->rpcproxy_address_index],
253                                              state->rpc_proxy_port,
254                                              state->credentials,
255                                              state->roh, state->tls,
256                                              state->tls_params);
257         if (tevent_req_nomem(subreq, state->req)) {
258                 return;
259         }
260         tevent_req_set_callback(subreq, roh_connect_channel_in_done, state->req);
261 }
262
263 static void roh_connect_channel_out_done(struct tevent_req *);
264 static void roh_connect_channel_in_done(struct tevent_req *subreq)
265 {
266         NTSTATUS                                status;
267         struct tevent_req                       *req;
268         struct roh_open_connection_state        *state;
269
270         req = tevent_req_callback_data(subreq, struct tevent_req);
271         state = tevent_req_data(req, struct roh_open_connection_state);
272
273         status = roh_connect_channel_in_recv(subreq);
274         TALLOC_FREE(subreq);
275         if (tevent_req_nterror(req, status)) {
276                 return;
277         }
278
279         subreq = roh_connect_channel_out_send(state,
280                                               state->event_ctx,
281                                               state->rpcproxy_addresses[state->rpcproxy_address_index],
282                                               state->rpc_proxy_port,
283                                               state->credentials,
284                                               state->roh,
285                                               state->tls,
286                                               state->tls_params);
287         if (tevent_req_nomem(subreq, req)) {
288                 return;
289         }
290         tevent_req_set_callback(subreq, roh_connect_channel_out_done, req);
291 }
292
293 static void roh_send_RPC_DATA_IN_done(struct tevent_req *);
294 static void roh_connect_channel_out_done(struct tevent_req *subreq)
295 {
296         NTSTATUS                                status;
297         struct tevent_req                       *req;
298         struct roh_open_connection_state        *state;
299
300         req = tevent_req_callback_data(subreq, struct tevent_req);
301         state = tevent_req_data(req, struct roh_open_connection_state);
302
303         status = roh_connect_channel_out_recv(subreq);
304         TALLOC_FREE(subreq);
305         if (tevent_req_nterror(req, status)) {
306                 return;
307         }
308
309         subreq = roh_send_RPC_DATA_IN_send(state, state->lp_ctx,
310                                            state->event_ctx,
311                                            state->credentials,
312                                            state->roh,
313                                            state->rpc_server,
314                                            state->rpc_server_port,
315                                            state->rpc_proxy,
316                                            state->use_ntlm);
317         if (tevent_req_nomem(subreq, req)) {
318                 return;
319         }
320         tevent_req_set_callback(subreq, roh_send_RPC_DATA_IN_done, req);
321 }
322
323 static void roh_send_RPC_DATA_OUT_done(struct tevent_req *);
324 static void roh_send_RPC_DATA_IN_done(struct tevent_req *subreq)
325 {
326         NTSTATUS                                status;
327         struct tevent_req                       *req;
328         struct roh_open_connection_state        *state;
329
330         req = tevent_req_callback_data(subreq, struct tevent_req);
331         state = tevent_req_data(req, struct roh_open_connection_state);
332
333         status = roh_send_RPC_DATA_IN_recv(subreq);
334         TALLOC_FREE(subreq);
335         if (tevent_req_nterror(req, status)) {
336                 return;
337         }
338
339         subreq = roh_send_RPC_DATA_OUT_send(state,
340                                             state->lp_ctx,
341                                             state->event_ctx,
342                                             state->credentials,
343                                             state->roh,
344                                             state->rpc_server,
345                                             state->rpc_server_port,
346                                             state->rpc_proxy,
347                                             state->use_ntlm);
348         if (tevent_req_nomem(subreq, req)) {
349                 return;
350         }
351         tevent_req_set_callback(subreq, roh_send_RPC_DATA_OUT_done, req);
352 }
353
354 static void roh_send_CONN_A1_done(struct tevent_req *);
355 static void roh_send_RPC_DATA_OUT_done(struct tevent_req *subreq)
356 {
357         NTSTATUS                                status;
358         struct tevent_req                       *req;
359         struct roh_open_connection_state        *state;
360
361         req = tevent_req_callback_data(subreq, struct tevent_req);
362         state = tevent_req_data(req, struct roh_open_connection_state);
363
364         status = roh_send_RPC_DATA_OUT_recv(subreq);
365         TALLOC_FREE(subreq);
366         if (tevent_req_nterror(req, status)) {
367                 return;
368         }
369
370         subreq = roh_send_CONN_A1_send(state, state->event_ctx, state->roh);
371         if (tevent_req_nomem(subreq, req)) {
372                 return;
373         }
374         tevent_req_set_callback(subreq, roh_send_CONN_A1_done, req);
375 }
376
377 static void roh_send_CONN_B1_done(struct tevent_req *);
378 static void roh_send_CONN_A1_done(struct tevent_req *subreq)
379 {
380         NTSTATUS                                status;
381         struct tevent_req                       *req;
382         struct roh_open_connection_state        *state;
383
384         req = tevent_req_callback_data(subreq, struct tevent_req);
385         state = tevent_req_data(req, struct roh_open_connection_state);
386
387         status = roh_send_CONN_A1_recv(subreq);
388         TALLOC_FREE(subreq);
389         if (tevent_req_nterror(req, status)) {
390                 return;
391         }
392
393         subreq = roh_send_CONN_B1_send(state, state->event_ctx, state->roh);
394         if (tevent_req_nomem(subreq, req)) {
395                 return;
396         }
397         tevent_req_set_callback(subreq, roh_send_CONN_B1_done, req);
398 }
399
400 static void roh_recv_out_channel_response_done(struct tevent_req *);
401 static void roh_send_CONN_B1_done(struct tevent_req *subreq)
402 {
403         NTSTATUS                                status;
404         struct tevent_req                       *req;
405         struct roh_open_connection_state        *state;
406
407         req = tevent_req_callback_data(subreq, struct tevent_req);
408         state = tevent_req_data(req, struct roh_open_connection_state);
409
410         status = roh_send_CONN_B1_recv(subreq);
411         TALLOC_FREE(subreq);
412         if (tevent_req_nterror(req, status)) {
413                 return;
414         }
415
416         state->roh->connection_state = ROH_STATE_OUT_CHANNEL_WAIT;
417         subreq = roh_recv_out_channel_response_send(state, state->event_ctx,
418                                                     state->roh);
419         if (tevent_req_nomem(subreq, req)) {
420                 return;
421         }
422         tevent_req_set_callback(subreq, roh_recv_out_channel_response_done, req);
423 }
424
425 static void roh_recv_CONN_A3_done(struct tevent_req *);
426 static void roh_recv_out_channel_response_done(struct tevent_req *subreq)
427 {
428         NTSTATUS                                status;
429         char                                    *response;
430         struct tevent_req                       *req;
431         struct roh_open_connection_state        *state;
432
433         req = tevent_req_callback_data(subreq, struct tevent_req);
434         state = tevent_req_data(req, struct roh_open_connection_state);
435
436         status = roh_recv_out_channel_response_recv(subreq, state, &response);
437         TALLOC_FREE(subreq);
438         if (tevent_req_nterror(req, status)) {
439                 return;
440         }
441
442         state->roh->connection_state = ROH_STATE_WAIT_A3W;
443         subreq = roh_recv_CONN_A3_send(state, state->event_ctx, state->roh);
444         if (tevent_req_nomem(subreq, req)) {
445                 return;
446         }
447         tevent_req_set_callback(subreq, roh_recv_CONN_A3_done, req);
448 }
449
450 static void roh_recv_CONN_C2_done(struct tevent_req *);
451 static void roh_recv_CONN_A3_done(struct tevent_req *subreq)
452 {
453         NTSTATUS                                status;
454         struct tevent_req                       *req;
455         struct roh_open_connection_state        *state;
456
457         req = tevent_req_callback_data(subreq, struct tevent_req);
458         state = tevent_req_data(req, struct roh_open_connection_state);
459
460         status = roh_recv_CONN_A3_recv(subreq, &state->roh->default_channel_out->connection_timeout);
461         TALLOC_FREE(subreq);
462         if (tevent_req_nterror(req, status)) {
463                 return;
464         }
465
466         state->roh->connection_state = ROH_STATE_WAIT_C2;
467         subreq = roh_recv_CONN_C2_send(state, state->event_ctx, state->roh);
468         if (tevent_req_nomem(subreq, req)) {
469                 return;
470         }
471         tevent_req_set_callback(subreq, roh_recv_CONN_C2_done, req);
472 }
473
474 static void roh_recv_CONN_C2_done(struct tevent_req *subreq)
475 {
476         NTSTATUS                                status;
477         struct tevent_req                       *req;
478         struct roh_open_connection_state        *state;
479         unsigned int                            version;
480         unsigned int                            recv;
481         unsigned int                            timeout;
482
483         req = tevent_req_callback_data(subreq, struct tevent_req);
484         state = tevent_req_data(req, struct roh_open_connection_state);
485
486         status = roh_recv_CONN_C2_recv(subreq, &version, &recv, &timeout);
487         TALLOC_FREE(subreq);
488         if (tevent_req_nterror(req, status)) {
489                 return;
490         }
491         state->roh->connection_state = ROH_STATE_OPENED;
492
493         tevent_req_done(req);
494 }
495
496 static ssize_t tstream_roh_pending_bytes(struct tstream_context *stream)
497 {
498         struct tstream_roh_context *ctx = NULL;
499
500         ctx = tstream_context_data(stream, struct tstream_roh_context);
501         if (!ctx->roh_conn) {
502                 errno = ENOTCONN;
503                 return -1;
504         }
505
506         return tstream_pending_bytes(ctx->roh_conn->default_channel_out->streams.active);
507 }
508
509 struct tstream_roh_readv_state {
510         struct roh_connection *roh_conn;
511         int ret;
512 };
513
514 static void tstream_roh_readv_handler(struct tevent_req *subreq);
515 static struct tevent_req * tstream_roh_readv_send(TALLOC_CTX *mem_ctx,
516                                                   struct tevent_context *ev,
517                                                   struct tstream_context *stream,
518                                                   struct iovec *vector,
519                                                   size_t count)
520 {
521         struct tstream_roh_context *ctx = NULL;
522         struct tstream_roh_readv_state *state;
523         struct tevent_req *req, *subreq;
524
525         req = tevent_req_create(mem_ctx, &state, struct tstream_roh_readv_state);
526         if (!req) {
527                 return NULL;
528         }
529
530         ctx = tstream_context_data(stream, struct tstream_roh_context);
531         if (!ctx->roh_conn) {
532                 tevent_req_error(req, ENOTCONN);
533                 goto post;
534         }
535         if (!ctx->roh_conn->default_channel_out) {
536                 tevent_req_error(req, ENOTCONN);
537                 goto post;
538         }
539         if (!ctx->roh_conn->default_channel_out->streams.active) {
540                 tevent_req_error(req, ENOTCONN);
541                 goto post;
542         }
543
544         state->roh_conn = ctx->roh_conn;
545
546         subreq = tstream_readv_send(state, ev,
547                                     ctx->roh_conn->default_channel_out->streams.active,
548                                     vector, count);
549         if (tevent_req_nomem(subreq, req)) {
550                 goto post;
551         }
552         tevent_req_set_callback(subreq, tstream_roh_readv_handler, req);
553
554         return req;
555 post:
556         tevent_req_post(req, ev);
557         return req;
558 }
559
560 static void tstream_roh_readv_handler(struct tevent_req *subreq)
561 {
562         struct tevent_req *req;
563         struct tstream_roh_readv_state *state;
564         int ret;
565         int sys_errno;
566
567         req = tevent_req_callback_data(subreq, struct tevent_req);
568         state = tevent_req_data(req, struct tstream_roh_readv_state);
569         ret = tstream_readv_recv(subreq, &sys_errno);
570         TALLOC_FREE(subreq);
571         if (ret == -1) {
572                 tevent_req_error(req, sys_errno);
573                 return;
574         }
575
576         state->ret = ret;
577
578         tevent_req_done(req);
579 }
580
581 static int tstream_roh_readv_recv(struct tevent_req *req, int *perrno)
582 {
583         struct tstream_roh_readv_state *state;
584         int ret;
585
586         state = tevent_req_data(req, struct tstream_roh_readv_state);
587         ret = tsocket_simple_int_recv(req, perrno);
588         if (ret == 0) {
589                 ret = state->ret;
590         }
591
592         tevent_req_received(req);
593         return ret;
594 }
595
596 struct tstream_roh_writev_state {
597         struct roh_connection *roh_conn;
598         int nwritten;
599 };
600
601 static void tstream_roh_writev_handler(struct tevent_req *subreq);
602 static struct tevent_req * tstream_roh_writev_send(TALLOC_CTX *mem_ctx,
603                                                    struct tevent_context *ev,
604                                                    struct tstream_context *stream,
605                                                    const struct iovec *vector,
606                                                    size_t count)
607 {
608         struct tstream_roh_context *ctx = NULL;
609         struct tstream_roh_writev_state *state = NULL;
610         struct tevent_req *req = NULL;
611         struct tevent_req *subreq = NULL;
612
613         req = tevent_req_create(mem_ctx, &state,
614                         struct tstream_roh_writev_state);
615         if (!req) {
616                 return NULL;
617         }
618
619         ctx = tstream_context_data(stream, struct tstream_roh_context);
620         if (!ctx->roh_conn) {
621                 tevent_req_error(req, ENOTCONN);
622                 goto post;
623         }
624         if (!ctx->roh_conn->default_channel_in) {
625                 tevent_req_error(req, ENOTCONN);
626                 goto post;
627         }
628         if (!ctx->roh_conn->default_channel_in->streams.active) {
629                 tevent_req_error(req, ENOTCONN);
630                 goto post;
631         }
632
633         state->roh_conn = ctx->roh_conn;
634
635         subreq = tstream_writev_send(state, ev,
636                                      ctx->roh_conn->default_channel_in->streams.active,
637                                      vector, count);
638         if (tevent_req_nomem(subreq, req)) {
639                 goto post;
640         }
641         tevent_req_set_callback(subreq, tstream_roh_writev_handler, req);
642
643         return req;
644 post:
645         tevent_req_post(req, ev);
646         return req;
647 }
648
649 static void tstream_roh_writev_handler(struct tevent_req *subreq)
650 {
651         struct tevent_req *req;
652         struct tstream_roh_writev_state *state;
653         int nwritten;
654         int sys_errno;
655
656         req = tevent_req_callback_data(subreq, struct tevent_req);
657         state = tevent_req_data(req, struct tstream_roh_writev_state);
658         nwritten = tstream_writev_recv(subreq, &sys_errno);
659         TALLOC_FREE(subreq);
660         if (nwritten == -1) {
661                 tevent_req_error(req, sys_errno);
662                 return;
663         }
664         state->nwritten = nwritten;
665         state->roh_conn->default_channel_in->sent_bytes += nwritten;
666
667         tevent_req_done(req);
668 }
669
670 static int tstream_roh_writev_recv(struct tevent_req *req, int *perrno)
671 {
672         struct tstream_roh_writev_state *state;
673         int ret;
674
675         state = tevent_req_data(req, struct tstream_roh_writev_state);
676         ret = tsocket_simple_int_recv(req, perrno);
677         if (ret == 0) {
678                 ret = state->nwritten;
679         }
680
681         return ret;
682 }
683
684 struct tstream_roh_disconnect_state {
685         struct tstream_context *stream;
686         struct tevent_context *ev;
687 };
688
689 static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq);
690 static struct tevent_req * tstream_roh_disconnect_send(TALLOC_CTX *mem_ctx,
691                                                        struct tevent_context *ev,
692                                                        struct tstream_context *stream)
693 {
694         struct tstream_roh_context *ctx = NULL;
695         struct tevent_req *req, *subreq;
696         struct tstream_roh_disconnect_state *state;
697
698         req = tevent_req_create(mem_ctx, &state, struct tstream_roh_disconnect_state);
699         if (req == NULL) {
700                 return NULL;
701         }
702
703         state->stream = stream;
704         state->ev = ev;
705
706         ctx = tstream_context_data(stream, struct tstream_roh_context);
707         if (!ctx->roh_conn) {
708                 tevent_req_error(req, ENOTCONN);
709                 goto post;
710         }
711         if (!ctx->roh_conn->default_channel_in) {
712                 tevent_req_error(req, ENOTCONN);
713                 goto post;
714         }
715         if (!ctx->roh_conn->default_channel_in->streams.active) {
716                 tevent_req_error(req, ENOTCONN);
717                 goto post;
718         }
719
720         subreq = tstream_disconnect_send(state, ev, ctx->roh_conn->default_channel_in->streams.active);
721         if (tevent_req_nomem(subreq, req)) {
722                 goto post;
723         }
724         tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_in_handler, req);
725
726         return req;
727 post:
728         tevent_req_post(req, ev);
729         return req;
730 }
731
732 static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq);
733
734 static void tstream_roh_disconnect_channel_in_handler(struct tevent_req *subreq)
735 {
736         struct tevent_req *req;
737         struct tstream_roh_disconnect_state *state;
738         struct tstream_context *stream;
739         struct tstream_roh_context *roh_stream;
740         int ret;
741         int sys_errno;
742
743         req = tevent_req_callback_data(subreq, struct tevent_req);
744         state = tevent_req_data(req, struct tstream_roh_disconnect_state);
745         stream = state->stream;
746         roh_stream = tstream_context_data(stream, struct tstream_roh_context);
747
748         ret = tstream_disconnect_recv(subreq, &sys_errno);
749         TALLOC_FREE(subreq);
750         if (ret == -1) {
751                 tevent_req_error(req, sys_errno);
752                 return;
753         }
754         TALLOC_FREE(roh_stream->roh_conn->default_channel_in);
755
756         subreq = tstream_disconnect_send(state,
757                                          state->ev,
758                                          roh_stream->roh_conn->default_channel_out->streams.raw);
759         if (tevent_req_nomem(subreq, req)) {
760                 return;
761         }
762         tevent_req_set_callback(subreq, tstream_roh_disconnect_channel_out_handler, req);
763
764         return;
765 }
766
767 static void tstream_roh_disconnect_channel_out_handler(struct tevent_req *subreq)
768 {
769         struct tevent_req *req;
770         struct tstream_roh_disconnect_state *state;
771         struct tstream_context *stream;
772         struct tstream_roh_context *roh_stream;
773         int ret;
774         int sys_errno;
775
776         req = tevent_req_callback_data(subreq, struct tevent_req);
777         state = tevent_req_data(req, struct tstream_roh_disconnect_state);
778         stream =  state->stream;
779         roh_stream = tstream_context_data(stream, struct tstream_roh_context);
780
781         ret = tstream_disconnect_recv(subreq, &sys_errno);
782         TALLOC_FREE(subreq);
783         if (ret == -1) {
784                 tevent_req_error(req, sys_errno);
785                 return;
786         }
787         TALLOC_FREE(roh_stream->roh_conn->default_channel_out);
788
789         tevent_req_done(req);
790 }
791
792 static int tstream_roh_disconnect_recv(struct tevent_req *req, int *perrno)
793 {
794         int ret;
795
796         ret = tsocket_simple_int_recv(req, perrno);
797         tevent_req_received(req);
798
799         return ret;
800 }