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
;
38 const struct dcerpc_binding
*binding
;
41 static const struct dcerpc_binding
*tstream_bh_get_binding(struct dcerpc_binding_handle
*h
)
43 struct tstream_bh_state
*hs
= dcerpc_binding_handle_data(
44 h
, struct tstream_bh_state
);
49 static bool tstream_bh_is_connected(struct dcerpc_binding_handle
*h
)
51 struct tstream_bh_state
*hs
= dcerpc_binding_handle_data(
52 h
, struct tstream_bh_state
);
55 if (hs
->stream
== NULL
) {
59 ret
= tstream_pending_bytes(hs
->stream
);
67 static uint32_t tstream_bh_set_timeout(struct dcerpc_binding_handle
*h
,
70 struct tstream_bh_state
*hs
= dcerpc_binding_handle_data(
71 h
, struct tstream_bh_state
);
74 old
= hs
->request_timeout
;
75 hs
->request_timeout
= timeout
;
80 struct tstream_bh_disconnect_state
{
81 struct tstream_bh_state
*hs
;
84 static void tstream_bh_disconnect_done(struct tevent_req
*subreq
);
86 static struct tevent_req
*tstream_bh_disconnect_send(
88 struct tevent_context
*ev
,
89 struct dcerpc_binding_handle
*h
)
91 struct tstream_bh_state
*hs
= dcerpc_binding_handle_data(
92 h
, struct tstream_bh_state
);
93 struct tevent_req
*req
= NULL
;
94 struct tstream_bh_disconnect_state
*state
= NULL
;
95 struct tevent_req
*subreq
= NULL
;
98 req
= tevent_req_create(mem_ctx
, &state
,
99 struct tstream_bh_disconnect_state
);
106 ok
= tstream_bh_is_connected(h
);
108 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
109 return tevent_req_post(req
, ev
);
112 subreq
= tstream_disconnect_send(state
, ev
, hs
->stream
);
113 if (tevent_req_nomem(subreq
, req
)) {
114 tevent_req_post(req
, ev
);
117 tevent_req_set_callback(subreq
, tstream_bh_disconnect_done
, req
);
122 static void tstream_bh_disconnect_done(struct tevent_req
*subreq
)
124 struct tevent_req
*req
= tevent_req_callback_data(
125 subreq
, struct tevent_req
);
126 struct tstream_bh_disconnect_state
*state
= tevent_req_data(
127 req
, struct tstream_bh_disconnect_state
);
130 ret
= tstream_disconnect_recv(subreq
, &err
);
133 DBG_ERR("tstream_bh_disconnect failed [%s]\n", strerror(err
));
134 tevent_req_nterror(req
, map_nt_error_from_unix_common(err
));
138 state
->hs
->stream
= NULL
;
141 static NTSTATUS
tstream_bh_disconnect_recv(struct tevent_req
*req
)
145 if (tevent_req_is_nterror(req
, &status
)) {
146 tevent_req_received(req
);
150 tevent_req_received(req
);
154 struct tstream_bh_call_state
{
155 struct tevent_context
*ev
;
156 struct tstream_context
*stream
;
157 struct tstream_bh_state
*hs
;
158 struct iovec out_data
;
162 static void tstream_bh_call_writev_done(struct tevent_req
*subreq
);
163 static void tstream_bh_call_read_pdu_done(struct tevent_req
*subreq
);
165 static struct tevent_req
*tstream_bh_call_send(TALLOC_CTX
*mem_ctx
,
166 struct tevent_context
*ev
,
167 struct dcerpc_binding_handle
*h
,
168 const struct GUID
*object
,
171 const uint8_t *out_data
,
174 struct tstream_bh_state
*hs
= dcerpc_binding_handle_data(
175 h
, struct tstream_bh_state
);
176 struct tevent_req
*req
= NULL
;
177 struct tevent_req
*subreq
= NULL
;
178 struct tstream_bh_call_state
* state
= NULL
;
179 struct timeval timeout
;
182 req
= tevent_req_create(mem_ctx
, &state
,
183 struct tstream_bh_call_state
);
188 *state
= (struct tstream_bh_call_state
) {
190 .stream
= hs
->stream
,
193 .iov_base
= discard_const_p(uint8_t, out_data
),
194 .iov_len
= out_length
,
198 ok
= tstream_bh_is_connected(h
);
200 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
201 return tevent_req_post(req
, ev
);
204 if (tstream_is_smbXcli_np(hs
->stream
)) {
205 tstream_smbXcli_np_use_trans(hs
->stream
);
207 if (tevent_queue_length(hs
->write_queue
) > 0) {
208 tevent_req_nterror(req
, NT_STATUS_PIPE_BUSY
);
211 timeout
= timeval_current_ofs(hs
->request_timeout
, 0);
213 subreq
= tstream_writev_queue_send(state
, ev
,
216 &state
->out_data
, 1);
217 if (tevent_req_nomem(subreq
, req
)) {
218 return tevent_req_post(req
, ev
);
220 if (!tevent_req_set_endtime(subreq
, ev
, timeout
)) {
221 return tevent_req_post(req
, ev
);
223 tevent_req_set_callback(subreq
, tstream_bh_call_writev_done
, req
);
225 subreq
= tstream_read_pdu_blob_send(state
,
228 hs
->call_initial_read_size
,
230 hs
->complete_pdu_fn_private
);
231 if (tevent_req_nomem(subreq
, req
)) {
232 return tevent_req_post(req
, ev
);
234 if (!tevent_req_set_endtime(subreq
, ev
, timeout
)) {
235 return tevent_req_post(req
, ev
);
237 tevent_req_set_callback(subreq
, tstream_bh_call_read_pdu_done
, req
);
242 static void tstream_bh_call_writev_done(struct tevent_req
*subreq
)
244 struct tevent_req
*req
= tevent_req_callback_data(
245 subreq
, struct tevent_req
);
246 struct tstream_bh_call_state
*state
= tevent_req_data(
247 req
, struct tstream_bh_call_state
);
250 ret
= tstream_writev_queue_recv(subreq
, &err
);
253 state
->hs
->stream
= NULL
;
254 tevent_req_nterror(req
, map_nt_error_from_unix_common(err
));
259 static void tstream_bh_call_read_pdu_done(struct tevent_req
*subreq
)
261 struct tevent_req
*req
= tevent_req_callback_data(
262 subreq
, struct tevent_req
);
263 struct tstream_bh_call_state
*state
= tevent_req_data(
264 req
, struct tstream_bh_call_state
);
267 status
= tstream_read_pdu_blob_recv(subreq
, state
, &state
->in_data
);
269 if (!NT_STATUS_IS_OK(status
)) {
270 state
->hs
->stream
= NULL
;
271 tevent_req_nterror(req
, status
);
275 tevent_req_done(req
);
278 static NTSTATUS
tstream_bh_call_recv(struct tevent_req
*req
,
285 struct tstream_bh_call_state
*state
= tevent_req_data(
286 req
, struct tstream_bh_call_state
);
288 if (tevent_req_is_nterror(req
, &status
)) {
289 tevent_req_received(req
);
293 *in_data
= talloc_move(mem_ctx
, &state
->in_data
.data
);
294 *in_length
= state
->in_data
.length
;
296 tevent_req_received(req
);
300 static const struct dcerpc_binding_handle_ops tstream_bh_ops
= {
301 .name
= "tstream_binding_handle",
302 .get_binding
= tstream_bh_get_binding
,
303 .is_connected
= tstream_bh_is_connected
,
304 .set_timeout
= tstream_bh_set_timeout
,
305 .raw_call_send
= tstream_bh_call_send
,
306 .raw_call_recv
= tstream_bh_call_recv
,
307 .disconnect_send
= tstream_bh_disconnect_send
,
308 .disconnect_recv
= tstream_bh_disconnect_recv
,
311 struct dcerpc_binding_handle
*tstream_binding_handle_create(
313 const struct ndr_interface_table
*table
,
314 struct tstream_context
**stream
,
315 size_t call_initial_read_size
,
316 tstream_read_pdu_blob_full_fn_t
*complete_pdu_fn
,
317 void *complete_pdu_fn_private
,
320 struct dcerpc_binding_handle
*h
= NULL
;
321 struct tstream_bh_state
*hs
= NULL
;
322 struct dcerpc_binding
*b
= NULL
;
325 h
= dcerpc_binding_handle_create(mem_ctx
,
330 struct tstream_bh_state
,
337 hs
->stream
= talloc_move(hs
, stream
);
338 hs
->call_initial_read_size
= call_initial_read_size
;
339 hs
->complete_pdu_fn
= complete_pdu_fn
;
340 hs
->complete_pdu_fn_private
= complete_pdu_fn_private
;
342 hs
->write_queue
= tevent_queue_create(hs
, "write_queue");
343 if (hs
->write_queue
== NULL
) {
348 status
= dcerpc_parse_binding(hs
, "", &b
);
349 if (!NT_STATUS_IS_OK(status
)) {
356 tstream_smbXcli_np_set_max_data(hs
->stream
, max_data
);