2 Unix SMB/CIFS implementation.
4 Copyright (C) Ralph Boehme 2016
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "libcli/tstream_binding_handle/tstream_binding_handle.h"
23 #include "system/filesys.h"
24 #include "lib/util/tevent_ntstatus.h"
25 #include "lib/tsocket/tsocket.h"
26 #include "lib/util/debug.h"
27 #include "lib/util/tevent_ntstatus.h"
28 #include "libcli/smb/tstream_smbXcli_np.h"
30 struct tstream_bh_state
{
31 struct tstream_context
*stream
;
32 struct tevent_queue
*write_queue
;
33 const struct ndr_interface_table
*table
;
34 uint32_t request_timeout
;
35 size_t call_initial_read_size
;
36 tstream_read_pdu_blob_full_fn_t
*complete_pdu_fn
;
37 void *complete_pdu_fn_private
;
40 static bool tstream_bh_is_connected(struct dcerpc_binding_handle
*h
)
42 struct tstream_bh_state
*hs
= dcerpc_binding_handle_data(
43 h
, struct tstream_bh_state
);
46 if (hs
->stream
== NULL
) {
50 ret
= tstream_pending_bytes(hs
->stream
);
58 static uint32_t tstream_bh_set_timeout(struct dcerpc_binding_handle
*h
,
61 struct tstream_bh_state
*hs
= dcerpc_binding_handle_data(
62 h
, struct tstream_bh_state
);
65 old
= hs
->request_timeout
;
66 hs
->request_timeout
= timeout
;
71 struct tstream_bh_disconnect_state
{
72 struct tstream_bh_state
*hs
;
75 static void tstream_bh_disconnect_done(struct tevent_req
*subreq
);
77 static struct tevent_req
*tstream_bh_disconnect_send(
79 struct tevent_context
*ev
,
80 struct dcerpc_binding_handle
*h
)
82 struct tstream_bh_state
*hs
= dcerpc_binding_handle_data(
83 h
, struct tstream_bh_state
);
84 struct tevent_req
*req
= NULL
;
85 struct tstream_bh_disconnect_state
*state
= NULL
;
86 struct tevent_req
*subreq
= NULL
;
89 req
= tevent_req_create(mem_ctx
, &state
,
90 struct tstream_bh_disconnect_state
);
97 ok
= tstream_bh_is_connected(h
);
99 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
100 return tevent_req_post(req
, ev
);
103 subreq
= tstream_disconnect_send(state
, ev
, hs
->stream
);
104 if (tevent_req_nomem(subreq
, req
)) {
105 tevent_req_post(req
, ev
);
108 tevent_req_set_callback(subreq
, tstream_bh_disconnect_done
, req
);
113 static void tstream_bh_disconnect_done(struct tevent_req
*subreq
)
115 struct tevent_req
*req
= tevent_req_callback_data(
116 subreq
, struct tevent_req
);
117 struct tstream_bh_disconnect_state
*state
= tevent_req_data(
118 req
, struct tstream_bh_disconnect_state
);
121 ret
= tstream_disconnect_recv(subreq
, &err
);
124 DBG_ERR("tstream_bh_disconnect failed [%s]\n", strerror(err
));
125 tevent_req_nterror(req
, map_nt_error_from_unix_common(err
));
129 state
->hs
->stream
= NULL
;
132 static NTSTATUS
tstream_bh_disconnect_recv(struct tevent_req
*req
)
136 if (tevent_req_is_nterror(req
, &status
)) {
137 tevent_req_received(req
);
141 tevent_req_received(req
);
145 struct tstream_bh_call_state
{
146 struct tevent_context
*ev
;
147 struct tstream_context
*stream
;
148 struct tstream_bh_state
*hs
;
149 struct iovec out_data
;
153 static void tstream_bh_call_writev_done(struct tevent_req
*subreq
);
154 static void tstream_bh_call_read_pdu_done(struct tevent_req
*subreq
);
156 static struct tevent_req
*tstream_bh_call_send(TALLOC_CTX
*mem_ctx
,
157 struct tevent_context
*ev
,
158 struct dcerpc_binding_handle
*h
,
159 const struct GUID
*object
,
162 const uint8_t *out_data
,
165 struct tstream_bh_state
*hs
= dcerpc_binding_handle_data(
166 h
, struct tstream_bh_state
);
167 struct tevent_req
*req
= NULL
;
168 struct tevent_req
*subreq
= NULL
;
169 struct tstream_bh_call_state
* state
= NULL
;
170 struct timeval timeout
;
173 req
= tevent_req_create(mem_ctx
, &state
,
174 struct tstream_bh_call_state
);
179 *state
= (struct tstream_bh_call_state
) {
181 .stream
= hs
->stream
,
184 .iov_base
= discard_const_p(uint8_t, out_data
),
185 .iov_len
= out_length
,
189 ok
= tstream_bh_is_connected(h
);
191 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
192 return tevent_req_post(req
, ev
);
195 if (tstream_is_smbXcli_np(hs
->stream
)) {
196 tstream_smbXcli_np_use_trans(hs
->stream
);
198 if (tevent_queue_length(hs
->write_queue
) > 0) {
199 tevent_req_nterror(req
, NT_STATUS_PIPE_BUSY
);
202 timeout
= timeval_current_ofs(hs
->request_timeout
, 0);
204 subreq
= tstream_writev_queue_send(state
, ev
,
207 &state
->out_data
, 1);
208 if (tevent_req_nomem(subreq
, req
)) {
209 return tevent_req_post(req
, ev
);
211 if (!tevent_req_set_endtime(subreq
, ev
, timeout
)) {
212 return tevent_req_post(req
, ev
);
214 tevent_req_set_callback(subreq
, tstream_bh_call_writev_done
, req
);
216 subreq
= tstream_read_pdu_blob_send(state
,
219 hs
->call_initial_read_size
,
221 hs
->complete_pdu_fn_private
);
222 if (tevent_req_nomem(subreq
, req
)) {
223 return tevent_req_post(req
, ev
);
225 if (!tevent_req_set_endtime(subreq
, ev
, timeout
)) {
226 return tevent_req_post(req
, ev
);
228 tevent_req_set_callback(subreq
, tstream_bh_call_read_pdu_done
, req
);
233 static void tstream_bh_call_writev_done(struct tevent_req
*subreq
)
235 struct tevent_req
*req
= tevent_req_callback_data(
236 subreq
, struct tevent_req
);
237 struct tstream_bh_call_state
*state
= tevent_req_data(
238 req
, struct tstream_bh_call_state
);
241 ret
= tstream_writev_queue_recv(subreq
, &err
);
244 state
->hs
->stream
= NULL
;
245 tevent_req_nterror(req
, map_nt_error_from_unix_common(err
));
250 static void tstream_bh_call_read_pdu_done(struct tevent_req
*subreq
)
252 struct tevent_req
*req
= tevent_req_callback_data(
253 subreq
, struct tevent_req
);
254 struct tstream_bh_call_state
*state
= tevent_req_data(
255 req
, struct tstream_bh_call_state
);
258 status
= tstream_read_pdu_blob_recv(subreq
, state
, &state
->in_data
);
260 if (!NT_STATUS_IS_OK(status
)) {
261 state
->hs
->stream
= NULL
;
262 tevent_req_nterror(req
, status
);
266 tevent_req_done(req
);
269 static NTSTATUS
tstream_bh_call_recv(struct tevent_req
*req
,
276 struct tstream_bh_call_state
*state
= tevent_req_data(
277 req
, struct tstream_bh_call_state
);
279 if (tevent_req_is_nterror(req
, &status
)) {
280 tevent_req_received(req
);
284 *in_data
= talloc_move(mem_ctx
, &state
->in_data
.data
);
285 *in_length
= state
->in_data
.length
;
287 tevent_req_received(req
);
291 static const struct dcerpc_binding_handle_ops tstream_bh_ops
= {
292 .name
= "tstream_binding_handle",
293 .is_connected
= tstream_bh_is_connected
,
294 .set_timeout
= tstream_bh_set_timeout
,
295 .raw_call_send
= tstream_bh_call_send
,
296 .raw_call_recv
= tstream_bh_call_recv
,
297 .disconnect_send
= tstream_bh_disconnect_send
,
298 .disconnect_recv
= tstream_bh_disconnect_recv
,
301 struct dcerpc_binding_handle
*tstream_binding_handle_create(
303 const struct ndr_interface_table
*table
,
304 struct tstream_context
**stream
,
305 size_t call_initial_read_size
,
306 tstream_read_pdu_blob_full_fn_t
*complete_pdu_fn
,
307 void *complete_pdu_fn_private
,
310 struct dcerpc_binding_handle
*h
= NULL
;
311 struct tstream_bh_state
*hs
= NULL
;
313 h
= dcerpc_binding_handle_create(mem_ctx
,
318 struct tstream_bh_state
,
325 hs
->stream
= talloc_move(hs
, stream
);
326 hs
->call_initial_read_size
= call_initial_read_size
;
327 hs
->complete_pdu_fn
= complete_pdu_fn
;
328 hs
->complete_pdu_fn_private
= complete_pdu_fn_private
;
330 hs
->write_queue
= tevent_queue_create(hs
, "write_queue");
331 if (hs
->write_queue
== NULL
) {
337 tstream_smbXcli_np_set_max_data(hs
->stream
, max_data
);