2 Unix SMB/CIFS implementation.
3 SMB client transport context management functions
5 Copyright (C) Andrew Tridgell 1994-2005
6 Copyright (C) James Myers 2003 <myersjj@samba.org>
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.
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.
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/>.
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"
38 static int transport_destructor(struct smbcli_transport
*transport
)
40 smbcli_transport_dead(transport
, NT_STATUS_LOCAL_DISCONNECT
);
45 create a transport structure based on an established socket
47 struct smbcli_transport
*smbcli_transport_init(struct smbcli_socket
*sock
,
48 TALLOC_CTX
*parent_ctx
,
50 struct smbcli_options
*options
)
52 struct smbcli_transport
*transport
;
53 uint32_t smb1_capabilities
;
55 transport
= talloc_zero(parent_ctx
, struct smbcli_transport
);
56 if (!transport
) return NULL
;
58 transport
->ev
= sock
->event
.ctx
;
59 transport
->options
= *options
;
61 TALLOC_FREE(sock
->event
.fde
);
62 TALLOC_FREE(sock
->event
.te
);
64 smb1_capabilities
= 0;
65 smb1_capabilities
|= CAP_LARGE_FILES
;
66 smb1_capabilities
|= CAP_NT_SMBS
| CAP_RPC_REMOTE_APIS
;
67 smb1_capabilities
|= CAP_LOCK_AND_READ
| CAP_NT_FIND
;
68 smb1_capabilities
|= CAP_DFS
| CAP_W2K_SMBS
;
69 smb1_capabilities
|= CAP_LARGE_READX
|CAP_LARGE_WRITEX
;
70 smb1_capabilities
|= CAP_LWIO
;
72 if (options
->ntstatus_support
) {
73 smb1_capabilities
|= CAP_STATUS32
;
76 if (options
->unicode
) {
77 smb1_capabilities
|= CAP_UNICODE
;
80 if (options
->use_spnego
) {
81 smb1_capabilities
|= CAP_EXTENDED_SECURITY
;
84 if (options
->use_level2_oplocks
) {
85 smb1_capabilities
|= CAP_LEVEL_II_OPLOCKS
;
88 transport
->conn
= smbXcli_conn_create(transport
,
93 NULL
, /* client_guid */
94 0); /* smb2_capabilities */
95 if (transport
->conn
== NULL
) {
97 TALLOC_FREE(transport
);
103 talloc_set_destructor(transport
, transport_destructor
);
109 mark the transport as dead
111 void smbcli_transport_dead(struct smbcli_transport
*transport
, NTSTATUS status
)
113 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL
, status
)) {
114 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
116 if (NT_STATUS_IS_OK(status
)) {
117 status
= NT_STATUS_LOCAL_DISCONNECT
;
120 smbXcli_conn_disconnect(transport
->conn
, status
);
123 static void idle_handler(struct tevent_context
*ev
,
124 struct tevent_timer
*te
, struct timeval t
, void *private_data
)
126 struct smbcli_transport
*transport
= talloc_get_type(private_data
,
127 struct smbcli_transport
);
130 transport
->idle
.func(transport
, transport
->idle
.private_data
);
132 next
= timeval_current_ofs_usec(transport
->idle
.period
);
134 transport
->idle
.te
= tevent_add_timer(transport
->ev
,
142 setup the idle handler for a transport
143 the period is in microseconds
145 _PUBLIC_
void smbcli_transport_idle_handler(struct smbcli_transport
*transport
,
146 void (*idle_func
)(struct smbcli_transport
*, void *),
150 TALLOC_FREE(transport
->idle
.te
);
152 transport
->idle
.func
= idle_func
;
153 transport
->idle
.private_data
= private_data
;
154 transport
->idle
.period
= period
;
156 transport
->idle
.te
= tevent_add_timer(transport
->ev
,
158 timeval_current_ofs_usec(period
),
164 process some read/write requests that are pending
165 return false if the socket is dead
167 _PUBLIC_
bool smbcli_transport_process(struct smbcli_transport
*transport
)
169 struct tevent_req
*subreq
= NULL
;
172 if (!smbXcli_conn_is_connected(transport
->conn
)) {
176 if (!smbXcli_conn_has_async_calls(transport
->conn
)) {
181 * do not block for more than 500 micro seconds
183 subreq
= tevent_wakeup_send(transport
,
185 timeval_current_ofs_usec(500));
186 if (subreq
== NULL
) {
190 ret
= tevent_loop_once(transport
->ev
);
197 if (!smbXcli_conn_is_connected(transport
->conn
)) {
204 static void smbcli_transport_break_handler(struct tevent_req
*subreq
);
205 static void smbcli_request_done(struct tevent_req
*subreq
);
207 struct tevent_req
*smbcli_transport_setup_subreq(struct smbcli_request
*req
)
209 struct smbcli_transport
*transport
= req
->transport
;
211 uint8_t additional_flags
;
213 uint16_t additional_flags2
;
214 uint16_t clear_flags2
;
216 struct smbXcli_tcon
*tcon
= NULL
;
217 struct smbXcli_session
*session
= NULL
;
218 uint32_t timeout_msec
= transport
->options
.request_timeout
* 1000;
219 struct iovec
*bytes_iov
= NULL
;
220 struct tevent_req
*subreq
= NULL
;
222 smb_command
= SVAL(req
->out
.hdr
, HDR_COM
);
223 additional_flags
= CVAL(req
->out
.hdr
, HDR_FLG
);
224 additional_flags2
= SVAL(req
->out
.hdr
, HDR_FLG2
);
225 pid
= SVAL(req
->out
.hdr
, HDR_PID
);
226 pid
|= SVAL(req
->out
.hdr
, HDR_PIDHIGH
)<<16;
228 clear_flags
= ~additional_flags
;
229 clear_flags2
= ~additional_flags2
;
232 session
= req
->session
->smbXcli
;
236 tcon
= req
->tree
->smbXcli
;
239 bytes_iov
= talloc(req
, struct iovec
);
240 if (bytes_iov
== NULL
) {
243 bytes_iov
->iov_base
= (void *)req
->out
.data
;
244 bytes_iov
->iov_len
= req
->out
.data_size
;
246 subreq
= smb1cli_req_create(req
,
259 (uint16_t *)req
->out
.vwv
,
261 if (subreq
== NULL
) {
265 ZERO_STRUCT(req
->out
);
271 put a request into the send queue
273 void smbcli_transport_send(struct smbcli_request
*req
)
275 struct smbcli_transport
*transport
= req
->transport
;
277 bool need_pending_break
= false;
278 struct tevent_req
*subreq
= NULL
;
280 size_t num_subreqs
= 0;
282 if (transport
->oplock
.handler
) {
283 need_pending_break
= true;
286 if (transport
->break_subreq
) {
287 need_pending_break
= false;
290 if (need_pending_break
) {
291 subreq
= smb1cli_req_create(transport
,
295 0, /* additional_flags */
297 0, /* additional_flags2 */
298 0, /* clear_flags2 */
299 0, /* timeout_msec */
306 NULL
); /* bytes_iov */
307 if (subreq
!= NULL
) {
308 smb1cli_req_set_mid(subreq
, 0xFFFF);
309 smbXcli_req_set_pending(subreq
);
310 tevent_req_set_callback(subreq
,
311 smbcli_transport_break_handler
,
313 transport
->break_subreq
= subreq
;
318 subreq
= smbcli_transport_setup_subreq(req
);
319 if (subreq
== NULL
) {
320 req
->state
= SMBCLI_REQUEST_ERROR
;
321 req
->status
= NT_STATUS_NO_MEMORY
;
325 for (i
= 0; i
< ARRAY_SIZE(req
->subreqs
); i
++) {
326 if (req
->subreqs
[i
] == NULL
) {
327 req
->subreqs
[i
] = subreq
;
330 if (req
->subreqs
[i
] == NULL
) {
334 if (!tevent_req_is_in_progress(req
->subreqs
[i
])) {
335 req
->state
= SMBCLI_REQUEST_ERROR
;
336 req
->status
= NT_STATUS_INTERNAL_ERROR
;
342 req
->state
= SMBCLI_REQUEST_RECV
;
343 tevent_req_set_callback(req
->subreqs
[0], smbcli_request_done
, req
);
345 status
= smb1cli_req_chain_submit(req
->subreqs
, num_subreqs
);
346 if (!NT_STATUS_IS_OK(status
)) {
347 req
->status
= status
;
348 req
->state
= SMBCLI_REQUEST_ERROR
;
349 smbXcli_conn_disconnect(transport
->conn
, status
);
353 static void smbcli_request_done(struct tevent_req
*subreq
)
355 struct smbcli_request
*req
=
356 tevent_req_callback_data(subreq
,
357 struct smbcli_request
);
358 struct smbcli_transport
*transport
= req
->transport
;
363 uint16_t *vwv
= NULL
;
364 uint32_t num_bytes
= 0;
365 uint8_t *bytes
= NULL
;
366 struct iovec
*recv_iov
= NULL
;
367 uint8_t *inbuf
= NULL
;
369 req
->status
= smb1cli_req_recv(req
->subreqs
[0], req
,
374 NULL
, /* pvwv_offset */
377 NULL
, /* pbytes_offset */
379 NULL
, 0); /* expected */
380 TALLOC_FREE(req
->subreqs
[0]);
381 if (!NT_STATUS_IS_OK(req
->status
)) {
382 if (recv_iov
== NULL
) {
383 req
->state
= SMBCLI_REQUEST_ERROR
;
384 transport
->error
.e
.nt_status
= req
->status
;
385 transport
->error
.etype
= ETYPE_SOCKET
;
394 * For SMBreadBraw hdr is NULL
396 len
= recv_iov
[0].iov_len
;
397 for (i
=1; hdr
!= NULL
&& i
< 3; i
++) {
398 uint8_t *p
= recv_iov
[i
-1].iov_base
;
399 uint8_t *c1
= recv_iov
[i
].iov_base
;
400 uint8_t *c2
= p
+ recv_iov
[i
-1].iov_len
;
402 len
+= recv_iov
[i
].iov_len
;
407 if (recv_iov
[i
].iov_len
== 0) {
412 req
->state
= SMBCLI_REQUEST_ERROR
;
413 req
->status
= NT_STATUS_INTERNAL_ERROR
;
414 transport
->error
.e
.nt_status
= req
->status
;
415 transport
->error
.etype
= ETYPE_SMB
;
423 /* fill in the 'in' portion of the matching request */
424 req
->in
.buffer
= inbuf
;
425 req
->in
.size
= NBT_HDR_SIZE
+ len
;
426 req
->in
.allocated
= req
->in
.size
;
429 req
->in
.vwv
= (uint8_t *)vwv
;
431 req
->in
.data
= bytes
;
432 req
->in
.data_size
= num_bytes
;
433 req
->in
.ptr
= req
->in
.data
;
435 req
->flags2
= SVAL(req
->in
.hdr
, HDR_FLG2
);
438 smb_setup_bufinfo(req
);
440 transport
->error
.e
.nt_status
= req
->status
;
441 if (NT_STATUS_IS_OK(req
->status
)) {
442 transport
->error
.etype
= ETYPE_NONE
;
444 transport
->error
.etype
= ETYPE_SMB
;
447 req
->state
= SMBCLI_REQUEST_DONE
;
453 static void smbcli_transport_break_handler(struct tevent_req
*subreq
)
455 struct smbcli_transport
*transport
=
456 tevent_req_callback_data(subreq
,
457 struct smbcli_transport
);
459 struct iovec
*recv_iov
= NULL
;
461 uint16_t *vwv
= NULL
;
462 const struct smb1cli_req_expected_response expected
[] = {
464 .status
= NT_STATUS_OK
,
472 transport
->break_subreq
= NULL
;
474 status
= smb1cli_req_recv(subreq
, transport
,
479 NULL
, /* pvwv_offset */
480 NULL
, /* pnum_bytes */
482 NULL
, /* pbytes_offset */
485 ARRAY_SIZE(expected
));
487 if (!NT_STATUS_IS_OK(status
)) {
488 TALLOC_FREE(recv_iov
);
489 smbcli_transport_dead(transport
, status
);
494 * Setup the subreq to handle the
495 * next incoming SMB2 Break.
497 subreq
= smb1cli_req_create(transport
,
501 0, /* additional_flags */
503 0, /* additional_flags2 */
504 0, /* clear_flags2 */
505 0, /* timeout_msec */
512 NULL
); /* bytes_iov */
513 if (subreq
!= NULL
) {
514 smb1cli_req_set_mid(subreq
, 0xFFFF);
515 smbXcli_req_set_pending(subreq
);
516 tevent_req_set_callback(subreq
,
517 smbcli_transport_break_handler
,
519 transport
->break_subreq
= subreq
;
522 tid
= SVAL(hdr
, HDR_TID
);
523 fnum
= SVAL(vwv
+2, 0);
524 level
= CVAL(vwv
+3, 1);
526 TALLOC_FREE(recv_iov
);
528 if (transport
->oplock
.handler
) {
529 transport
->oplock
.handler(transport
, tid
, fnum
, level
,
530 transport
->oplock
.private_data
);
532 DEBUG(5,("Got SMB oplock break with no handler\n"));
538 /****************************************************************************
539 Send an SMBecho (async send)
540 *****************************************************************************/
541 _PUBLIC_
struct smbcli_request
*smb_raw_echo_send(struct smbcli_transport
*transport
,
544 struct smbcli_request
*req
;
546 req
= smbcli_request_setup_transport(transport
, SMBecho
, 1, p
->in
.size
);
547 if (!req
) return NULL
;
549 SSVAL(req
->out
.vwv
, VWV(0), p
->in
.repeat_count
);
551 memcpy(req
->out
.data
, p
->in
.data
, p
->in
.size
);
555 if (!smbcli_request_send(req
)) {
556 smbcli_request_destroy(req
);
563 /****************************************************************************
564 raw echo interface (async recv)
565 ****************************************************************************/
566 NTSTATUS
smb_raw_echo_recv(struct smbcli_request
*req
, TALLOC_CTX
*mem_ctx
,
569 if (!smbcli_request_receive(req
) ||
570 smbcli_request_is_error(req
)) {
574 SMBCLI_CHECK_WCT(req
, 1);
576 p
->out
.sequence_number
= SVAL(req
->in
.vwv
, VWV(0));
577 p
->out
.size
= req
->in
.data_size
;
578 talloc_free(p
->out
.data
);
579 p
->out
.data
= talloc_array(mem_ctx
, uint8_t, p
->out
.size
);
580 NT_STATUS_HAVE_NO_MEMORY(p
->out
.data
);
582 if (!smbcli_raw_pull_data(&req
->in
.bufinfo
, req
->in
.data
, p
->out
.size
, p
->out
.data
)) {
583 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
586 if (p
->out
.count
== p
->in
.repeat_count
) {
587 return smbcli_request_destroy(req
);
593 return smbcli_request_destroy(req
);
596 /****************************************************************************
597 Send a echo (sync interface)
598 *****************************************************************************/
599 NTSTATUS
smb_raw_echo(struct smbcli_transport
*transport
, struct smb_echo
*p
)
601 struct smbcli_request
*req
= smb_raw_echo_send(transport
, p
);
602 return smbcli_request_simple_recv(req
);