/src/samba/source4/libcli/raw/clitransport.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | SMB client transport context management functions |
4 | | |
5 | | Copyright (C) Andrew Tridgell 1994-2005 |
6 | | Copyright (C) James Myers 2003 <myersjj@samba.org> |
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 "system/network.h" |
24 | | #include "../lib/async_req/async_sock.h" |
25 | | #include "../lib/util/tevent_ntstatus.h" |
26 | | #include "libcli/raw/libcliraw.h" |
27 | | #include "libcli/raw/raw_proto.h" |
28 | | #include "lib/socket/socket.h" |
29 | | #include "lib/events/events.h" |
30 | | #include "librpc/gen_ndr/ndr_nbt.h" |
31 | | #include "../libcli/nbt/libnbt.h" |
32 | | #include "../libcli/smb/smbXcli_base.h" |
33 | | #include "../libcli/smb/read_smb.h" |
34 | | |
35 | | /* |
36 | | destroy a transport |
37 | | */ |
38 | | static int transport_destructor(struct smbcli_transport *transport) |
39 | 0 | { |
40 | 0 | smbcli_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT); |
41 | 0 | return 0; |
42 | 0 | } |
43 | | |
44 | | /* |
45 | | create a transport structure based on an established socket |
46 | | */ |
47 | | struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock, |
48 | | TALLOC_CTX *parent_ctx, |
49 | | bool primary, |
50 | | struct smbcli_options *options) |
51 | 0 | { |
52 | 0 | struct smbcli_transport *transport; |
53 | 0 | uint32_t smb1_capabilities; |
54 | |
|
55 | 0 | transport = talloc_zero(parent_ctx, struct smbcli_transport); |
56 | 0 | if (!transport) return NULL; |
57 | | |
58 | 0 | transport->ev = sock->event.ctx; |
59 | 0 | transport->options = *options; |
60 | |
|
61 | 0 | if (transport->options.max_protocol == PROTOCOL_DEFAULT) { |
62 | 0 | transport->options.max_protocol = PROTOCOL_NT1; |
63 | 0 | } |
64 | |
|
65 | 0 | if (transport->options.max_protocol > PROTOCOL_NT1) { |
66 | 0 | transport->options.max_protocol = PROTOCOL_NT1; |
67 | 0 | } |
68 | |
|
69 | 0 | smb1_capabilities = 0; |
70 | 0 | smb1_capabilities |= CAP_LARGE_FILES; |
71 | 0 | smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS; |
72 | 0 | smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND; |
73 | 0 | smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS; |
74 | 0 | smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX; |
75 | 0 | smb1_capabilities |= CAP_LWIO; |
76 | |
|
77 | 0 | if (options->ntstatus_support) { |
78 | 0 | smb1_capabilities |= CAP_STATUS32; |
79 | 0 | } |
80 | |
|
81 | 0 | if (options->unicode) { |
82 | 0 | smb1_capabilities |= CAP_UNICODE; |
83 | 0 | } |
84 | |
|
85 | 0 | if (options->use_spnego) { |
86 | 0 | smb1_capabilities |= CAP_EXTENDED_SECURITY; |
87 | 0 | } |
88 | |
|
89 | 0 | if (options->use_level2_oplocks) { |
90 | 0 | smb1_capabilities |= CAP_LEVEL_II_OPLOCKS; |
91 | 0 | } |
92 | |
|
93 | 0 | transport->conn = smbXcli_conn_create(transport, |
94 | 0 | &sock->transport, |
95 | 0 | sock->hostname, |
96 | 0 | options->signing, |
97 | 0 | smb1_capabilities, |
98 | 0 | NULL, /* client_guid */ |
99 | 0 | 0, /* smb2_capabilities */ |
100 | 0 | NULL); /* smb3_ciphers */ |
101 | 0 | TALLOC_FREE(sock); |
102 | 0 | if (transport->conn == NULL) { |
103 | 0 | TALLOC_FREE(transport); |
104 | 0 | return NULL; |
105 | 0 | } |
106 | | |
107 | 0 | talloc_set_destructor(transport, transport_destructor); |
108 | |
|
109 | 0 | return transport; |
110 | 0 | } |
111 | | |
112 | | /* |
113 | | create a transport structure based on an established socket |
114 | | */ |
115 | | NTSTATUS smbcli_transport_raw_init(TALLOC_CTX *mem_ctx, |
116 | | struct tevent_context *ev, |
117 | | struct smbXcli_conn **_conn, |
118 | | const struct smbcli_options *options, |
119 | | struct smbcli_transport **_transport) |
120 | 0 | { |
121 | 0 | struct smbcli_transport *transport = NULL; |
122 | 0 | NTSTATUS status; |
123 | |
|
124 | 0 | if (*_conn == NULL) { |
125 | 0 | return NT_STATUS_INVALID_PARAMETER; |
126 | 0 | } |
127 | | |
128 | 0 | transport = talloc_zero(mem_ctx, struct smbcli_transport); |
129 | 0 | if (transport == NULL) { |
130 | 0 | return NT_STATUS_NO_MEMORY; |
131 | 0 | } |
132 | | |
133 | 0 | transport->ev = ev; |
134 | 0 | transport->options = *options; |
135 | | |
136 | | /* |
137 | | * First only set the pointer without move. |
138 | | */ |
139 | 0 | transport->conn = *_conn; |
140 | 0 | status = smb_raw_negotiate_fill_transport(transport); |
141 | 0 | if (!NT_STATUS_IS_OK(status)) { |
142 | 0 | TALLOC_FREE(transport); |
143 | 0 | return status; |
144 | 0 | } |
145 | | |
146 | 0 | talloc_set_destructor(transport, transport_destructor); |
147 | | |
148 | | /* |
149 | | * Now move it away from the caller... |
150 | | */ |
151 | 0 | transport->conn = talloc_move(transport, _conn); |
152 | 0 | *_transport = transport; |
153 | 0 | return NT_STATUS_OK; |
154 | 0 | } |
155 | | |
156 | | /* |
157 | | mark the transport as dead |
158 | | */ |
159 | | void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status) |
160 | 0 | { |
161 | 0 | if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) { |
162 | 0 | status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; |
163 | 0 | } |
164 | 0 | if (NT_STATUS_IS_OK(status)) { |
165 | 0 | status = NT_STATUS_LOCAL_DISCONNECT; |
166 | 0 | } |
167 | |
|
168 | 0 | smbXcli_conn_disconnect(transport->conn, status); |
169 | 0 | } |
170 | | |
171 | | static void idle_handler(struct tevent_context *ev, |
172 | | struct tevent_timer *te, struct timeval t, void *private_data) |
173 | 0 | { |
174 | 0 | struct smbcli_transport *transport = talloc_get_type(private_data, |
175 | 0 | struct smbcli_transport); |
176 | 0 | struct timeval next; |
177 | |
|
178 | 0 | transport->idle.func(transport, transport->idle.private_data); |
179 | |
|
180 | 0 | if (transport->idle.func == NULL) { |
181 | 0 | return; |
182 | 0 | } |
183 | | |
184 | 0 | if (!smbXcli_conn_is_connected(transport->conn)) { |
185 | 0 | return; |
186 | 0 | } |
187 | | |
188 | 0 | next = timeval_current_ofs_usec(transport->idle.period); |
189 | |
|
190 | 0 | transport->idle.te = tevent_add_timer(transport->ev, |
191 | 0 | transport, |
192 | 0 | next, |
193 | 0 | idle_handler, |
194 | 0 | transport); |
195 | 0 | } |
196 | | |
197 | | /* |
198 | | setup the idle handler for a transport |
199 | | the period is in microseconds |
200 | | */ |
201 | | _PUBLIC_ void smbcli_transport_idle_handler(struct smbcli_transport *transport, |
202 | | void (*idle_func)(struct smbcli_transport *, void *), |
203 | | uint64_t period, |
204 | | void *private_data) |
205 | 0 | { |
206 | 0 | TALLOC_FREE(transport->idle.te); |
207 | 0 | ZERO_STRUCT(transport->idle); |
208 | |
|
209 | 0 | if (idle_func == NULL) { |
210 | 0 | return; |
211 | 0 | } |
212 | | |
213 | 0 | if (!smbXcli_conn_is_connected(transport->conn)) { |
214 | 0 | return; |
215 | 0 | } |
216 | | |
217 | 0 | transport->idle.func = idle_func; |
218 | 0 | transport->idle.private_data = private_data; |
219 | 0 | transport->idle.period = period; |
220 | |
|
221 | 0 | transport->idle.te = tevent_add_timer(transport->ev, |
222 | 0 | transport, |
223 | 0 | timeval_current_ofs_usec(period), |
224 | 0 | idle_handler, |
225 | 0 | transport); |
226 | 0 | } |
227 | | |
228 | | /* |
229 | | process some read/write requests that are pending |
230 | | return false if the socket is dead |
231 | | */ |
232 | | _PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport) |
233 | 0 | { |
234 | 0 | struct tevent_req *subreq = NULL; |
235 | 0 | int ret; |
236 | |
|
237 | 0 | if (!smbXcli_conn_is_connected(transport->conn)) { |
238 | 0 | return false; |
239 | 0 | } |
240 | | |
241 | 0 | if (!smbXcli_conn_has_async_calls(transport->conn)) { |
242 | 0 | return true; |
243 | 0 | } |
244 | | |
245 | | /* |
246 | | * do not block for more than 500 micro seconds |
247 | | */ |
248 | 0 | subreq = tevent_wakeup_send(transport, |
249 | 0 | transport->ev, |
250 | 0 | timeval_current_ofs_usec(500)); |
251 | 0 | if (subreq == NULL) { |
252 | 0 | return false; |
253 | 0 | } |
254 | | |
255 | 0 | ret = tevent_loop_once(transport->ev); |
256 | 0 | if (ret != 0) { |
257 | 0 | return false; |
258 | 0 | } |
259 | | |
260 | 0 | TALLOC_FREE(subreq); |
261 | |
|
262 | 0 | if (!smbXcli_conn_is_connected(transport->conn)) { |
263 | 0 | return false; |
264 | 0 | } |
265 | | |
266 | 0 | return true; |
267 | 0 | } |
268 | | |
269 | | static void smbcli_transport_break_handler(struct tevent_req *subreq); |
270 | | static void smbcli_request_done(struct tevent_req *subreq); |
271 | | |
272 | | struct tevent_req *smbcli_transport_setup_subreq(struct smbcli_request *req) |
273 | 0 | { |
274 | 0 | struct smbcli_transport *transport = req->transport; |
275 | 0 | uint8_t smb_command; |
276 | 0 | uint8_t additional_flags; |
277 | 0 | uint8_t clear_flags; |
278 | 0 | uint16_t additional_flags2; |
279 | 0 | uint16_t clear_flags2; |
280 | 0 | uint32_t pid; |
281 | 0 | struct smbXcli_tcon *tcon = NULL; |
282 | 0 | struct smbXcli_session *session = NULL; |
283 | 0 | uint32_t timeout_msec = transport->options.request_timeout * 1000; |
284 | 0 | struct iovec *bytes_iov = NULL; |
285 | 0 | struct tevent_req *subreq = NULL; |
286 | |
|
287 | 0 | smb_command = SVAL(req->out.hdr, HDR_COM); |
288 | 0 | additional_flags = CVAL(req->out.hdr, HDR_FLG); |
289 | 0 | additional_flags2 = SVAL(req->out.hdr, HDR_FLG2); |
290 | 0 | pid = SVAL(req->out.hdr, HDR_PID); |
291 | 0 | pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16; |
292 | |
|
293 | 0 | clear_flags = ~additional_flags; |
294 | 0 | clear_flags2 = ~additional_flags2; |
295 | |
|
296 | 0 | if (req->session) { |
297 | 0 | session = req->session->smbXcli; |
298 | 0 | } |
299 | |
|
300 | 0 | if (req->tree) { |
301 | 0 | tcon = req->tree->smbXcli; |
302 | 0 | } |
303 | |
|
304 | 0 | bytes_iov = talloc(req, struct iovec); |
305 | 0 | if (bytes_iov == NULL) { |
306 | 0 | return NULL; |
307 | 0 | } |
308 | 0 | bytes_iov->iov_base = (void *)req->out.data; |
309 | 0 | bytes_iov->iov_len = req->out.data_size; |
310 | |
|
311 | 0 | subreq = smb1cli_req_create(req, |
312 | 0 | transport->ev, |
313 | 0 | transport->conn, |
314 | 0 | smb_command, |
315 | 0 | additional_flags, |
316 | 0 | clear_flags, |
317 | 0 | additional_flags2, |
318 | 0 | clear_flags2, |
319 | 0 | timeout_msec, |
320 | 0 | pid, |
321 | 0 | tcon, |
322 | 0 | session, |
323 | 0 | req->out.wct, |
324 | 0 | (uint16_t *)req->out.vwv, |
325 | 0 | 1, bytes_iov); |
326 | 0 | if (subreq == NULL) { |
327 | 0 | return NULL; |
328 | 0 | } |
329 | | |
330 | 0 | ZERO_STRUCT(req->out); |
331 | |
|
332 | 0 | return subreq; |
333 | 0 | } |
334 | | |
335 | | /* |
336 | | put a request into the send queue |
337 | | */ |
338 | | void smbcli_transport_send(struct smbcli_request *req) |
339 | 0 | { |
340 | 0 | struct smbcli_transport *transport = req->transport; |
341 | 0 | NTSTATUS status; |
342 | 0 | bool need_pending_break = false; |
343 | 0 | struct tevent_req *subreq = NULL; |
344 | 0 | size_t i; |
345 | 0 | size_t num_subreqs = 0; |
346 | |
|
347 | 0 | if (transport->oplock.handler) { |
348 | 0 | need_pending_break = true; |
349 | 0 | } |
350 | |
|
351 | 0 | if (transport->break_subreq) { |
352 | 0 | need_pending_break = false; |
353 | 0 | } |
354 | |
|
355 | 0 | if (need_pending_break) { |
356 | 0 | subreq = smb1cli_req_create(transport, |
357 | 0 | transport->ev, |
358 | 0 | transport->conn, |
359 | 0 | 0, /* smb_command */ |
360 | 0 | 0, /* additional_flags */ |
361 | 0 | 0, /* clear_flags */ |
362 | 0 | 0, /* additional_flags2 */ |
363 | 0 | 0, /* clear_flags2 */ |
364 | 0 | 0, /* timeout_msec */ |
365 | 0 | 0, /* pid */ |
366 | 0 | NULL, /* tcon */ |
367 | 0 | NULL, /* session */ |
368 | 0 | 0, /* wct */ |
369 | 0 | NULL, /* vwv */ |
370 | 0 | 0, /* iov_count */ |
371 | 0 | NULL); /* bytes_iov */ |
372 | 0 | if (subreq != NULL) { |
373 | 0 | smb1cli_req_set_mid(subreq, 0xFFFF); |
374 | 0 | smbXcli_req_set_pending(subreq); |
375 | 0 | tevent_req_set_callback(subreq, |
376 | 0 | smbcli_transport_break_handler, |
377 | 0 | transport); |
378 | 0 | transport->break_subreq = subreq; |
379 | 0 | subreq = NULL; |
380 | 0 | } |
381 | 0 | } |
382 | |
|
383 | 0 | subreq = smbcli_transport_setup_subreq(req); |
384 | 0 | if (subreq == NULL) { |
385 | 0 | req->state = SMBCLI_REQUEST_ERROR; |
386 | 0 | req->status = NT_STATUS_NO_MEMORY; |
387 | 0 | return; |
388 | 0 | } |
389 | | |
390 | 0 | for (i = 0; i < ARRAY_SIZE(req->subreqs); i++) { |
391 | 0 | if (req->subreqs[i] == NULL) { |
392 | 0 | req->subreqs[i] = subreq; |
393 | 0 | subreq = NULL; |
394 | 0 | } |
395 | 0 | if (req->subreqs[i] == NULL) { |
396 | 0 | break; |
397 | 0 | } |
398 | | |
399 | 0 | if (!tevent_req_is_in_progress(req->subreqs[i])) { |
400 | 0 | req->state = SMBCLI_REQUEST_ERROR; |
401 | 0 | req->status = NT_STATUS_INTERNAL_ERROR; |
402 | 0 | return; |
403 | 0 | } |
404 | 0 | } |
405 | 0 | num_subreqs = i; |
406 | |
|
407 | 0 | req->state = SMBCLI_REQUEST_RECV; |
408 | 0 | tevent_req_set_callback(req->subreqs[0], smbcli_request_done, req); |
409 | |
|
410 | 0 | status = smb1cli_req_chain_submit(req->subreqs, num_subreqs); |
411 | 0 | if (!NT_STATUS_IS_OK(status)) { |
412 | 0 | req->status = status; |
413 | 0 | req->state = SMBCLI_REQUEST_ERROR; |
414 | 0 | smbXcli_conn_disconnect(transport->conn, status); |
415 | 0 | } |
416 | 0 | } |
417 | | |
418 | | static void smbcli_request_done(struct tevent_req *subreq) |
419 | 0 | { |
420 | 0 | struct smbcli_request *req = |
421 | 0 | tevent_req_callback_data(subreq, |
422 | 0 | struct smbcli_request); |
423 | 0 | struct smbcli_transport *transport = req->transport; |
424 | 0 | ssize_t len; |
425 | 0 | size_t i; |
426 | 0 | uint8_t *hdr = NULL; |
427 | 0 | uint8_t wct = 0; |
428 | 0 | uint16_t *vwv = NULL; |
429 | 0 | uint32_t num_bytes = 0; |
430 | 0 | uint8_t *bytes = NULL; |
431 | 0 | struct iovec *recv_iov = NULL; |
432 | 0 | uint8_t *inbuf = NULL; |
433 | |
|
434 | 0 | req->status = smb1cli_req_recv(req->subreqs[0], req, |
435 | 0 | &recv_iov, |
436 | 0 | &hdr, |
437 | 0 | &wct, |
438 | 0 | &vwv, |
439 | 0 | NULL, /* pvwv_offset */ |
440 | 0 | &num_bytes, |
441 | 0 | &bytes, |
442 | 0 | NULL, /* pbytes_offset */ |
443 | 0 | &inbuf, |
444 | 0 | NULL, 0); /* expected */ |
445 | 0 | TALLOC_FREE(req->subreqs[0]); |
446 | 0 | if (!NT_STATUS_IS_OK(req->status)) { |
447 | 0 | if (recv_iov == NULL) { |
448 | 0 | req->state = SMBCLI_REQUEST_ERROR; |
449 | 0 | transport->error.e.nt_status = req->status; |
450 | 0 | transport->error.etype = ETYPE_SOCKET; |
451 | 0 | if (req->async.fn) { |
452 | 0 | req->async.fn(req); |
453 | 0 | } |
454 | 0 | return; |
455 | 0 | } |
456 | 0 | } |
457 | | |
458 | | /* |
459 | | * For SMBreadBraw hdr is NULL |
460 | | */ |
461 | 0 | len = recv_iov[0].iov_len; |
462 | 0 | for (i=1; hdr != NULL && i < 3; i++) { |
463 | 0 | uint8_t *p = recv_iov[i-1].iov_base; |
464 | 0 | uint8_t *c1 = recv_iov[i].iov_base; |
465 | 0 | uint8_t *c2 = p + recv_iov[i-1].iov_len; |
466 | |
|
467 | 0 | len += recv_iov[i].iov_len; |
468 | |
|
469 | 0 | c2 += i; |
470 | 0 | len += i; |
471 | |
|
472 | 0 | if (recv_iov[i].iov_len == 0) { |
473 | 0 | continue; |
474 | 0 | } |
475 | | |
476 | 0 | if (c1 != c2) { |
477 | 0 | req->state = SMBCLI_REQUEST_ERROR; |
478 | 0 | req->status = NT_STATUS_INTERNAL_ERROR; |
479 | 0 | transport->error.e.nt_status = req->status; |
480 | 0 | transport->error.etype = ETYPE_SMB; |
481 | 0 | if (req->async.fn) { |
482 | 0 | req->async.fn(req); |
483 | 0 | } |
484 | 0 | return; |
485 | 0 | } |
486 | 0 | } |
487 | | |
488 | | /* fill in the 'in' portion of the matching request */ |
489 | 0 | req->in.buffer = inbuf; |
490 | 0 | req->in.size = NBT_HDR_SIZE + len; |
491 | 0 | req->in.allocated = req->in.size; |
492 | |
|
493 | 0 | req->in.hdr = hdr; |
494 | 0 | req->in.vwv = (uint8_t *)vwv; |
495 | 0 | req->in.wct = wct; |
496 | 0 | req->in.data = bytes; |
497 | 0 | req->in.data_size = num_bytes; |
498 | 0 | req->in.ptr = req->in.data; |
499 | 0 | if (hdr != NULL) { |
500 | 0 | req->flags2 = SVAL(req->in.hdr, HDR_FLG2); |
501 | 0 | } |
502 | |
|
503 | 0 | smb_setup_bufinfo(req); |
504 | |
|
505 | 0 | transport->error.e.nt_status = req->status; |
506 | 0 | if (NT_STATUS_IS_OK(req->status)) { |
507 | 0 | transport->error.etype = ETYPE_NONE; |
508 | 0 | } else { |
509 | 0 | transport->error.etype = ETYPE_SMB; |
510 | 0 | } |
511 | |
|
512 | 0 | req->state = SMBCLI_REQUEST_DONE; |
513 | 0 | if (req->async.fn) { |
514 | 0 | req->async.fn(req); |
515 | 0 | } |
516 | 0 | } |
517 | | |
518 | | static void smbcli_transport_break_handler(struct tevent_req *subreq) |
519 | 0 | { |
520 | 0 | struct smbcli_transport *transport = |
521 | 0 | tevent_req_callback_data(subreq, |
522 | 0 | struct smbcli_transport); |
523 | 0 | NTSTATUS status; |
524 | 0 | struct iovec *recv_iov = NULL; |
525 | 0 | uint8_t *hdr = NULL; |
526 | 0 | uint16_t *vwv = NULL; |
527 | 0 | const struct smb1cli_req_expected_response expected[] = { |
528 | 0 | { |
529 | 0 | .status = NT_STATUS_OK, |
530 | 0 | .wct = 8, |
531 | 0 | } |
532 | 0 | }; |
533 | 0 | uint16_t tid; |
534 | 0 | uint16_t fnum; |
535 | 0 | uint8_t level; |
536 | |
|
537 | 0 | transport->break_subreq = NULL; |
538 | |
|
539 | 0 | status = smb1cli_req_recv(subreq, transport, |
540 | 0 | &recv_iov, |
541 | 0 | &hdr, |
542 | 0 | NULL, /* pwct */ |
543 | 0 | &vwv, |
544 | 0 | NULL, /* pvwv_offset */ |
545 | 0 | NULL, /* pnum_bytes */ |
546 | 0 | NULL, /* pbytes */ |
547 | 0 | NULL, /* pbytes_offset */ |
548 | 0 | NULL, /* pinbuf */ |
549 | 0 | expected, |
550 | 0 | ARRAY_SIZE(expected)); |
551 | 0 | TALLOC_FREE(subreq); |
552 | 0 | if (!NT_STATUS_IS_OK(status)) { |
553 | 0 | TALLOC_FREE(recv_iov); |
554 | 0 | smbcli_transport_dead(transport, status); |
555 | 0 | return; |
556 | 0 | } |
557 | | |
558 | | /* |
559 | | * Setup the subreq to handle the |
560 | | * next incoming SMB2 Break. |
561 | | */ |
562 | 0 | subreq = smb1cli_req_create(transport, |
563 | 0 | transport->ev, |
564 | 0 | transport->conn, |
565 | 0 | 0, /* smb_command */ |
566 | 0 | 0, /* additional_flags */ |
567 | 0 | 0, /* clear_flags */ |
568 | 0 | 0, /* additional_flags2 */ |
569 | 0 | 0, /* clear_flags2 */ |
570 | 0 | 0, /* timeout_msec */ |
571 | 0 | 0, /* pid */ |
572 | 0 | NULL, /* tcon */ |
573 | 0 | NULL, /* session */ |
574 | 0 | 0, /* wct */ |
575 | 0 | NULL, /* vwv */ |
576 | 0 | 0, /* iov_count */ |
577 | 0 | NULL); /* bytes_iov */ |
578 | 0 | if (subreq != NULL) { |
579 | 0 | smb1cli_req_set_mid(subreq, 0xFFFF); |
580 | 0 | smbXcli_req_set_pending(subreq); |
581 | 0 | tevent_req_set_callback(subreq, |
582 | 0 | smbcli_transport_break_handler, |
583 | 0 | transport); |
584 | 0 | transport->break_subreq = subreq; |
585 | 0 | } |
586 | |
|
587 | 0 | tid = SVAL(hdr, HDR_TID); |
588 | 0 | fnum = SVAL(vwv+2, 0); |
589 | 0 | level = CVAL(vwv+3, 1); |
590 | |
|
591 | 0 | TALLOC_FREE(recv_iov); |
592 | |
|
593 | 0 | if (transport->oplock.handler) { |
594 | 0 | transport->oplock.handler(transport, tid, fnum, level, |
595 | 0 | transport->oplock.private_data); |
596 | 0 | } else { |
597 | 0 | DEBUG(5,("Got SMB oplock break with no handler\n")); |
598 | 0 | } |
599 | |
|
600 | 0 | } |
601 | | |
602 | | |
603 | | /**************************************************************************** |
604 | | Send an SMBecho (async send) |
605 | | *****************************************************************************/ |
606 | | _PUBLIC_ struct smbcli_request *smb_raw_echo_send(struct smbcli_transport *transport, |
607 | | struct smb_echo *p) |
608 | 0 | { |
609 | 0 | struct smbcli_request *req; |
610 | |
|
611 | 0 | req = smbcli_request_setup_transport(transport, SMBecho, 1, p->in.size); |
612 | 0 | if (!req) return NULL; |
613 | | |
614 | 0 | SSVAL(req->out.vwv, VWV(0), p->in.repeat_count); |
615 | |
|
616 | 0 | memcpy(req->out.data, p->in.data, p->in.size); |
617 | |
|
618 | 0 | ZERO_STRUCT(p->out); |
619 | |
|
620 | 0 | if (!smbcli_request_send(req)) { |
621 | 0 | smbcli_request_destroy(req); |
622 | 0 | return NULL; |
623 | 0 | } |
624 | | |
625 | 0 | return req; |
626 | 0 | } |
627 | | |
628 | | /**************************************************************************** |
629 | | raw echo interface (async recv) |
630 | | ****************************************************************************/ |
631 | | NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, |
632 | | struct smb_echo *p) |
633 | 0 | { |
634 | 0 | if (!smbcli_request_receive(req) || |
635 | 0 | smbcli_request_is_error(req)) { |
636 | 0 | goto failed; |
637 | 0 | } |
638 | | |
639 | 0 | SMBCLI_CHECK_WCT(req, 1); |
640 | 0 | p->out.count++; |
641 | 0 | p->out.sequence_number = SVAL(req->in.vwv, VWV(0)); |
642 | 0 | p->out.size = req->in.data_size; |
643 | 0 | talloc_free(p->out.data); |
644 | 0 | p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size); |
645 | 0 | NT_STATUS_HAVE_NO_MEMORY(p->out.data); |
646 | | |
647 | 0 | if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) { |
648 | 0 | req->status = NT_STATUS_BUFFER_TOO_SMALL; |
649 | 0 | } |
650 | |
|
651 | 0 | if (p->out.count == p->in.repeat_count) { |
652 | 0 | return smbcli_request_destroy(req); |
653 | 0 | } |
654 | | |
655 | 0 | return NT_STATUS_OK; |
656 | | |
657 | 0 | failed: |
658 | 0 | return smbcli_request_destroy(req); |
659 | 0 | } |
660 | | |
661 | | /**************************************************************************** |
662 | | Send a echo (sync interface) |
663 | | *****************************************************************************/ |
664 | | NTSTATUS smb_raw_echo(struct smbcli_transport *transport, struct smb_echo *p) |
665 | 0 | { |
666 | 0 | struct smbcli_request *req = smb_raw_echo_send(transport, p); |
667 | 0 | return smbcli_request_simple_recv(req); |
668 | 0 | } |