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 if (transport->options.max_protocol == PROTOCOL_DEFAULT) {
62 transport->options.max_protocol = PROTOCOL_NT1;
65 if (transport->options.max_protocol > PROTOCOL_NT1) {
66 transport->options.max_protocol = PROTOCOL_NT1;
69 TALLOC_FREE(sock->event.fde);
70 TALLOC_FREE(sock->event.te);
72 smb1_capabilities = 0;
73 smb1_capabilities |= CAP_LARGE_FILES;
74 smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
75 smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND;
76 smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS;
77 smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX;
78 smb1_capabilities |= CAP_LWIO;
80 if (options->ntstatus_support) {
81 smb1_capabilities |= CAP_STATUS32;
84 if (options->unicode) {
85 smb1_capabilities |= CAP_UNICODE;
88 if (options->use_spnego) {
89 smb1_capabilities |= CAP_EXTENDED_SECURITY;
92 if (options->use_level2_oplocks) {
93 smb1_capabilities |= CAP_LEVEL_II_OPLOCKS;
96 transport->conn = smbXcli_conn_create(transport,
101 NULL, /* client_guid */
102 0); /* smb2_capabilities */
103 if (transport->conn == NULL) {
105 TALLOC_FREE(transport);
111 talloc_set_destructor(transport, transport_destructor);
117 mark the transport as dead
119 void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status)
121 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
122 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
124 if (NT_STATUS_IS_OK(status)) {
125 status = NT_STATUS_LOCAL_DISCONNECT;
128 smbXcli_conn_disconnect(transport->conn, status);
131 static void idle_handler(struct tevent_context *ev,
132 struct tevent_timer *te, struct timeval t, void *private_data)
134 struct smbcli_transport *transport = talloc_get_type(private_data,
135 struct smbcli_transport);
138 transport->idle.func(transport, transport->idle.private_data);
140 next = timeval_current_ofs_usec(transport->idle.period);
142 transport->idle.te = tevent_add_timer(transport->ev,
150 setup the idle handler for a transport
151 the period is in microseconds
153 _PUBLIC_ void smbcli_transport_idle_handler(struct smbcli_transport *transport,
154 void (*idle_func)(struct smbcli_transport *, void *),
158 TALLOC_FREE(transport->idle.te);
160 transport->idle.func = idle_func;
161 transport->idle.private_data = private_data;
162 transport->idle.period = period;
164 transport->idle.te = tevent_add_timer(transport->ev,
166 timeval_current_ofs_usec(period),
172 process some read/write requests that are pending
173 return false if the socket is dead
175 _PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport)
177 struct tevent_req *subreq = NULL;
180 if (!smbXcli_conn_is_connected(transport->conn)) {
184 if (!smbXcli_conn_has_async_calls(transport->conn)) {
189 * do not block for more than 500 micro seconds
191 subreq = tevent_wakeup_send(transport,
193 timeval_current_ofs_usec(500));
194 if (subreq == NULL) {
198 ret = tevent_loop_once(transport->ev);
205 if (!smbXcli_conn_is_connected(transport->conn)) {
212 static void smbcli_transport_break_handler(struct tevent_req *subreq);
213 static void smbcli_request_done(struct tevent_req *subreq);
215 struct tevent_req *smbcli_transport_setup_subreq(struct smbcli_request *req)
217 struct smbcli_transport *transport = req->transport;
219 uint8_t additional_flags;
221 uint16_t additional_flags2;
222 uint16_t clear_flags2;
224 struct smbXcli_tcon *tcon = NULL;
225 struct smbXcli_session *session = NULL;
226 uint32_t timeout_msec = transport->options.request_timeout * 1000;
227 struct iovec *bytes_iov = NULL;
228 struct tevent_req *subreq = NULL;
230 smb_command = SVAL(req->out.hdr, HDR_COM);
231 additional_flags = CVAL(req->out.hdr, HDR_FLG);
232 additional_flags2 = SVAL(req->out.hdr, HDR_FLG2);
233 pid = SVAL(req->out.hdr, HDR_PID);
234 pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16;
236 clear_flags = ~additional_flags;
237 clear_flags2 = ~additional_flags2;
240 session = req->session->smbXcli;
244 tcon = req->tree->smbXcli;
247 bytes_iov = talloc(req, struct iovec);
248 if (bytes_iov == NULL) {
251 bytes_iov->iov_base = (void *)req->out.data;
252 bytes_iov->iov_len = req->out.data_size;
254 subreq = smb1cli_req_create(req,
267 (uint16_t *)req->out.vwv,
269 if (subreq == NULL) {
273 ZERO_STRUCT(req->out);
279 put a request into the send queue
281 void smbcli_transport_send(struct smbcli_request *req)
283 struct smbcli_transport *transport = req->transport;
285 bool need_pending_break = false;
286 struct tevent_req *subreq = NULL;
288 size_t num_subreqs = 0;
290 if (transport->oplock.handler) {
291 need_pending_break = true;
294 if (transport->break_subreq) {
295 need_pending_break = false;
298 if (need_pending_break) {
299 subreq = smb1cli_req_create(transport,
303 0, /* additional_flags */
305 0, /* additional_flags2 */
306 0, /* clear_flags2 */
307 0, /* timeout_msec */
314 NULL); /* bytes_iov */
315 if (subreq != NULL) {
316 smb1cli_req_set_mid(subreq, 0xFFFF);
317 smbXcli_req_set_pending(subreq);
318 tevent_req_set_callback(subreq,
319 smbcli_transport_break_handler,
321 transport->break_subreq = subreq;
326 subreq = smbcli_transport_setup_subreq(req);
327 if (subreq == NULL) {
328 req->state = SMBCLI_REQUEST_ERROR;
329 req->status = NT_STATUS_NO_MEMORY;
333 for (i = 0; i < ARRAY_SIZE(req->subreqs); i++) {
334 if (req->subreqs[i] == NULL) {
335 req->subreqs[i] = subreq;
338 if (req->subreqs[i] == NULL) {
342 if (!tevent_req_is_in_progress(req->subreqs[i])) {
343 req->state = SMBCLI_REQUEST_ERROR;
344 req->status = NT_STATUS_INTERNAL_ERROR;
350 req->state = SMBCLI_REQUEST_RECV;
351 tevent_req_set_callback(req->subreqs[0], smbcli_request_done, req);
353 status = smb1cli_req_chain_submit(req->subreqs, num_subreqs);
354 if (!NT_STATUS_IS_OK(status)) {
355 req->status = status;
356 req->state = SMBCLI_REQUEST_ERROR;
357 smbXcli_conn_disconnect(transport->conn, status);
361 static void smbcli_request_done(struct tevent_req *subreq)
363 struct smbcli_request *req =
364 tevent_req_callback_data(subreq,
365 struct smbcli_request);
366 struct smbcli_transport *transport = req->transport;
371 uint16_t *vwv = NULL;
372 uint32_t num_bytes = 0;
373 uint8_t *bytes = NULL;
374 struct iovec *recv_iov = NULL;
375 uint8_t *inbuf = NULL;
377 req->status = smb1cli_req_recv(req->subreqs[0], req,
382 NULL, /* pvwv_offset */
385 NULL, /* pbytes_offset */
387 NULL, 0); /* expected */
388 TALLOC_FREE(req->subreqs[0]);
389 if (!NT_STATUS_IS_OK(req->status)) {
390 if (recv_iov == NULL) {
391 req->state = SMBCLI_REQUEST_ERROR;
392 transport->error.e.nt_status = req->status;
393 transport->error.etype = ETYPE_SOCKET;
402 * For SMBreadBraw hdr is NULL
404 len = recv_iov[0].iov_len;
405 for (i=1; hdr != NULL && i < 3; i++) {
406 uint8_t *p = recv_iov[i-1].iov_base;
407 uint8_t *c1 = recv_iov[i].iov_base;
408 uint8_t *c2 = p + recv_iov[i-1].iov_len;
410 len += recv_iov[i].iov_len;
415 if (recv_iov[i].iov_len == 0) {
420 req->state = SMBCLI_REQUEST_ERROR;
421 req->status = NT_STATUS_INTERNAL_ERROR;
422 transport->error.e.nt_status = req->status;
423 transport->error.etype = ETYPE_SMB;
431 /* fill in the 'in' portion of the matching request */
432 req->in.buffer = inbuf;
433 req->in.size = NBT_HDR_SIZE + len;
434 req->in.allocated = req->in.size;
437 req->in.vwv = (uint8_t *)vwv;
439 req->in.data = bytes;
440 req->in.data_size = num_bytes;
441 req->in.ptr = req->in.data;
443 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
446 smb_setup_bufinfo(req);
448 transport->error.e.nt_status = req->status;
449 if (NT_STATUS_IS_OK(req->status)) {
450 transport->error.etype = ETYPE_NONE;
452 transport->error.etype = ETYPE_SMB;
455 req->state = SMBCLI_REQUEST_DONE;
461 static void smbcli_transport_break_handler(struct tevent_req *subreq)
463 struct smbcli_transport *transport =
464 tevent_req_callback_data(subreq,
465 struct smbcli_transport);
467 struct iovec *recv_iov = NULL;
469 uint16_t *vwv = NULL;
470 const struct smb1cli_req_expected_response expected[] = {
472 .status = NT_STATUS_OK,
480 transport->break_subreq = NULL;
482 status = smb1cli_req_recv(subreq, transport,
487 NULL, /* pvwv_offset */
488 NULL, /* pnum_bytes */
490 NULL, /* pbytes_offset */
493 ARRAY_SIZE(expected));
495 if (!NT_STATUS_IS_OK(status)) {
496 TALLOC_FREE(recv_iov);
497 smbcli_transport_dead(transport, status);
502 * Setup the subreq to handle the
503 * next incoming SMB2 Break.
505 subreq = smb1cli_req_create(transport,
509 0, /* additional_flags */
511 0, /* additional_flags2 */
512 0, /* clear_flags2 */
513 0, /* timeout_msec */
520 NULL); /* bytes_iov */
521 if (subreq != NULL) {
522 smb1cli_req_set_mid(subreq, 0xFFFF);
523 smbXcli_req_set_pending(subreq);
524 tevent_req_set_callback(subreq,
525 smbcli_transport_break_handler,
527 transport->break_subreq = subreq;
530 tid = SVAL(hdr, HDR_TID);
531 fnum = SVAL(vwv+2, 0);
532 level = CVAL(vwv+3, 1);
534 TALLOC_FREE(recv_iov);
536 if (transport->oplock.handler) {
537 transport->oplock.handler(transport, tid, fnum, level,
538 transport->oplock.private_data);
540 DEBUG(5,("Got SMB oplock break with no handler\n"));
546 /****************************************************************************
547 Send an SMBecho (async send)
548 *****************************************************************************/
549 _PUBLIC_ struct smbcli_request *smb_raw_echo_send(struct smbcli_transport *transport,
552 struct smbcli_request *req;
554 req = smbcli_request_setup_transport(transport, SMBecho, 1, p->in.size);
555 if (!req) return NULL;
557 SSVAL(req->out.vwv, VWV(0), p->in.repeat_count);
559 memcpy(req->out.data, p->in.data, p->in.size);
563 if (!smbcli_request_send(req)) {
564 smbcli_request_destroy(req);
571 /****************************************************************************
572 raw echo interface (async recv)
573 ****************************************************************************/
574 NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
577 if (!smbcli_request_receive(req) ||
578 smbcli_request_is_error(req)) {
582 SMBCLI_CHECK_WCT(req, 1);
584 p->out.sequence_number = SVAL(req->in.vwv, VWV(0));
585 p->out.size = req->in.data_size;
586 talloc_free(p->out.data);
587 p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size);
588 NT_STATUS_HAVE_NO_MEMORY(p->out.data);
590 if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) {
591 req->status = NT_STATUS_BUFFER_TOO_SMALL;
594 if (p->out.count == p->in.repeat_count) {
595 return smbcli_request_destroy(req);
601 return smbcli_request_destroy(req);
604 /****************************************************************************
605 Send a echo (sync interface)
606 *****************************************************************************/
607 NTSTATUS smb_raw_echo(struct smbcli_transport *transport, struct smb_echo *p)
609 struct smbcli_request *req = smb_raw_echo_send(transport, p);
610 return smbcli_request_simple_recv(req);