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