libcli/smb: pass down smbXcli_session to smb1cli_req_create/send() and smb1cli_trans*
[Samba/gebeck_regimport.git] / source4 / libcli / raw / clitransport.c
blob321df768f2f35f398d6bfe03e1e1a3cc5a23f5ac
1 /*
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/>.
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"
36 destroy a transport
38 static int transport_destructor(struct smbcli_transport *transport)
40 smbcli_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT);
41 return 0;
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,
49 bool primary,
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,
89 sock->sock->fd,
90 sock->hostname,
91 options->signing,
92 smb1_capabilities,
93 NULL, /* client_guid */
94 0); /* smb2_capabilities */
95 if (transport->conn == NULL) {
96 TALLOC_FREE(sock);
97 TALLOC_FREE(transport);
98 return NULL;
100 sock->sock->fd = -1;
101 TALLOC_FREE(sock);
103 talloc_set_destructor(transport, transport_destructor);
105 return transport;
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);
128 struct timeval next;
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,
135 transport,
136 next,
137 idle_handler,
138 transport);
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 *),
147 uint64_t period,
148 void *private_data)
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,
157 transport,
158 timeval_current_ofs_usec(period),
159 idle_handler,
160 transport);
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;
170 int ret;
172 if (!smbXcli_conn_is_connected(transport->conn)) {
173 return false;
176 if (!smbXcli_conn_has_async_calls(transport->conn)) {
177 return true;
181 * do not block for more than 500 micro seconds
183 subreq = tevent_wakeup_send(transport,
184 transport->ev,
185 timeval_current_ofs_usec(500));
186 if (subreq == NULL) {
187 return false;
190 ret = tevent_loop_once(transport->ev);
191 if (ret != 0) {
192 return false;
195 TALLOC_FREE(subreq);
197 if (!smbXcli_conn_is_connected(transport->conn)) {
198 return false;
201 return true;
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;
210 uint8_t smb_command;
211 uint8_t additional_flags;
212 uint8_t clear_flags;
213 uint16_t additional_flags2;
214 uint16_t clear_flags2;
215 uint32_t pid;
216 uint16_t tid;
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;
227 tid = SVAL(req->out.hdr, HDR_TID);
229 clear_flags = ~additional_flags;
230 clear_flags2 = ~additional_flags2;
232 if (req->session) {
233 session = req->session->smbXcli;
236 bytes_iov = talloc(req, struct iovec);
237 if (bytes_iov == NULL) {
238 return NULL;
240 bytes_iov->iov_base = (void *)req->out.data;
241 bytes_iov->iov_len = req->out.data_size;
243 subreq = smb1cli_req_create(req,
244 transport->ev,
245 transport->conn,
246 smb_command,
247 additional_flags,
248 clear_flags,
249 additional_flags2,
250 clear_flags2,
251 timeout_msec,
252 pid,
253 tid,
254 session,
255 req->out.wct,
256 (uint16_t *)req->out.vwv,
257 1, bytes_iov);
258 if (subreq == NULL) {
259 return NULL;
262 ZERO_STRUCT(req->out);
264 return subreq;
268 put a request into the send queue
270 void smbcli_transport_send(struct smbcli_request *req)
272 struct smbcli_transport *transport = req->transport;
273 NTSTATUS status;
274 bool need_pending_break = false;
275 struct tevent_req *subreq = NULL;
276 size_t i;
277 size_t num_subreqs = 0;
279 if (transport->oplock.handler) {
280 need_pending_break = true;
283 if (transport->break_subreq) {
284 need_pending_break = false;
287 if (need_pending_break) {
288 subreq = smb1cli_req_create(transport,
289 transport->ev,
290 transport->conn,
291 0, /* smb_command */
292 0, /* additional_flags */
293 0, /* clear_flags */
294 0, /* additional_flags2 */
295 0, /* clear_flags2 */
296 0, /* timeout_msec */
297 0, /* pid */
298 0, /* tid */
299 NULL, /* session */
300 0, /* wct */
301 NULL, /* vwv */
302 0, /* iov_count */
303 NULL); /* bytes_iov */
304 if (subreq != NULL) {
305 smb1cli_req_set_mid(subreq, 0xFFFF);
306 smbXcli_req_set_pending(subreq);
307 tevent_req_set_callback(subreq,
308 smbcli_transport_break_handler,
309 transport);
310 transport->break_subreq = subreq;
311 subreq = NULL;
315 subreq = smbcli_transport_setup_subreq(req);
316 if (subreq == NULL) {
317 req->state = SMBCLI_REQUEST_ERROR;
318 req->status = NT_STATUS_NO_MEMORY;
319 return;
322 for (i = 0; i < ARRAY_SIZE(req->subreqs); i++) {
323 if (req->subreqs[i] == NULL) {
324 req->subreqs[i] = subreq;
325 subreq = NULL;
327 if (req->subreqs[i] == NULL) {
328 break;
331 if (!tevent_req_is_in_progress(req->subreqs[i])) {
332 req->state = SMBCLI_REQUEST_ERROR;
333 req->status = NT_STATUS_INTERNAL_ERROR;
334 return;
337 num_subreqs = i;
339 req->state = SMBCLI_REQUEST_RECV;
340 tevent_req_set_callback(req->subreqs[0], smbcli_request_done, req);
342 status = smb1cli_req_chain_submit(req->subreqs, num_subreqs);
343 if (!NT_STATUS_IS_OK(status)) {
344 req->status = status;
345 req->state = SMBCLI_REQUEST_ERROR;
346 smbXcli_conn_disconnect(transport->conn, status);
350 static void smbcli_request_done(struct tevent_req *subreq)
352 struct smbcli_request *req =
353 tevent_req_callback_data(subreq,
354 struct smbcli_request);
355 struct smbcli_transport *transport = req->transport;
356 ssize_t len;
357 size_t i;
358 uint8_t *hdr = NULL;
359 uint8_t wct = 0;
360 uint16_t *vwv = NULL;
361 uint32_t num_bytes = 0;
362 uint8_t *bytes = NULL;
363 struct iovec *recv_iov = NULL;
364 uint8_t *inbuf = NULL;
366 req->status = smb1cli_req_recv(req->subreqs[0], req,
367 &recv_iov,
368 &hdr,
369 &wct,
370 &vwv,
371 NULL, /* pvwv_offset */
372 &num_bytes,
373 &bytes,
374 NULL, /* pbytes_offset */
375 &inbuf,
376 NULL, 0); /* expected */
377 TALLOC_FREE(req->subreqs[0]);
378 if (!NT_STATUS_IS_OK(req->status)) {
379 if (recv_iov == NULL) {
380 req->state = SMBCLI_REQUEST_ERROR;
381 transport->error.e.nt_status = req->status;
382 transport->error.etype = ETYPE_SOCKET;
383 if (req->async.fn) {
384 req->async.fn(req);
386 return;
391 * For SMBreadBraw hdr is NULL
393 len = recv_iov[0].iov_len;
394 for (i=1; hdr != NULL && i < 3; i++) {
395 uint8_t *p = recv_iov[i-1].iov_base;
396 uint8_t *c1 = recv_iov[i].iov_base;
397 uint8_t *c2 = p + recv_iov[i-1].iov_len;
399 len += recv_iov[i].iov_len;
401 c2 += i;
402 len += i;
404 if (recv_iov[i].iov_len == 0) {
405 continue;
408 if (c1 != c2) {
409 req->state = SMBCLI_REQUEST_ERROR;
410 req->status = NT_STATUS_INTERNAL_ERROR;
411 transport->error.e.nt_status = req->status;
412 transport->error.etype = ETYPE_SMB;
413 if (req->async.fn) {
414 req->async.fn(req);
416 return;
420 /* fill in the 'in' portion of the matching request */
421 req->in.buffer = inbuf;
422 req->in.size = NBT_HDR_SIZE + len;
423 req->in.allocated = req->in.size;
425 req->in.hdr = hdr;
426 req->in.vwv = (uint8_t *)vwv;
427 req->in.wct = wct;
428 req->in.data = bytes;
429 req->in.data_size = num_bytes;
430 req->in.ptr = req->in.data;
431 if (hdr != NULL) {
432 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
435 smb_setup_bufinfo(req);
437 transport->error.e.nt_status = req->status;
438 if (NT_STATUS_IS_OK(req->status)) {
439 transport->error.etype = ETYPE_NONE;
440 } else {
441 transport->error.etype = ETYPE_SMB;
444 req->state = SMBCLI_REQUEST_DONE;
445 if (req->async.fn) {
446 req->async.fn(req);
450 static void smbcli_transport_break_handler(struct tevent_req *subreq)
452 struct smbcli_transport *transport =
453 tevent_req_callback_data(subreq,
454 struct smbcli_transport);
455 NTSTATUS status;
456 struct iovec *recv_iov = NULL;
457 uint8_t *hdr = NULL;
458 uint16_t *vwv = NULL;
459 const struct smb1cli_req_expected_response expected[] = {
461 .status = NT_STATUS_OK,
462 .wct = 8,
465 uint16_t tid;
466 uint16_t fnum;
467 uint8_t level;
469 transport->break_subreq = NULL;
471 status = smb1cli_req_recv(subreq, transport,
472 &recv_iov,
473 &hdr,
474 NULL, /* pwct */
475 &vwv,
476 NULL, /* pvwv_offset */
477 NULL, /* pnum_bytes */
478 NULL, /* pbytes */
479 NULL, /* pbytes_offset */
480 NULL, /* pinbuf */
481 expected,
482 ARRAY_SIZE(expected));
483 TALLOC_FREE(subreq);
484 if (!NT_STATUS_IS_OK(status)) {
485 TALLOC_FREE(recv_iov);
486 smbcli_transport_dead(transport, status);
487 return;
491 * Setup the subreq to handle the
492 * next incoming SMB2 Break.
494 subreq = smb1cli_req_create(transport,
495 transport->ev,
496 transport->conn,
497 0, /* smb_command */
498 0, /* additional_flags */
499 0, /* clear_flags */
500 0, /* additional_flags2 */
501 0, /* clear_flags2 */
502 0, /* timeout_msec */
503 0, /* pid */
504 0, /* tid */
505 NULL, /* session */
506 0, /* wct */
507 NULL, /* vwv */
508 0, /* iov_count */
509 NULL); /* bytes_iov */
510 if (subreq != NULL) {
511 smb1cli_req_set_mid(subreq, 0xFFFF);
512 smbXcli_req_set_pending(subreq);
513 tevent_req_set_callback(subreq,
514 smbcli_transport_break_handler,
515 transport);
516 transport->break_subreq = subreq;
519 tid = SVAL(hdr, HDR_TID);
520 fnum = SVAL(vwv+2, 0);
521 level = CVAL(vwv+3, 1);
523 TALLOC_FREE(recv_iov);
525 if (transport->oplock.handler) {
526 transport->oplock.handler(transport, tid, fnum, level,
527 transport->oplock.private_data);
528 } else {
529 DEBUG(5,("Got SMB oplock break with no handler\n"));
535 /****************************************************************************
536 Send an SMBecho (async send)
537 *****************************************************************************/
538 _PUBLIC_ struct smbcli_request *smb_raw_echo_send(struct smbcli_transport *transport,
539 struct smb_echo *p)
541 struct smbcli_request *req;
543 req = smbcli_request_setup_transport(transport, SMBecho, 1, p->in.size);
544 if (!req) return NULL;
546 SSVAL(req->out.vwv, VWV(0), p->in.repeat_count);
548 memcpy(req->out.data, p->in.data, p->in.size);
550 ZERO_STRUCT(p->out);
552 if (!smbcli_request_send(req)) {
553 smbcli_request_destroy(req);
554 return NULL;
557 return req;
560 /****************************************************************************
561 raw echo interface (async recv)
562 ****************************************************************************/
563 NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
564 struct smb_echo *p)
566 if (!smbcli_request_receive(req) ||
567 smbcli_request_is_error(req)) {
568 goto failed;
571 SMBCLI_CHECK_WCT(req, 1);
572 p->out.count++;
573 p->out.sequence_number = SVAL(req->in.vwv, VWV(0));
574 p->out.size = req->in.data_size;
575 talloc_free(p->out.data);
576 p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size);
577 NT_STATUS_HAVE_NO_MEMORY(p->out.data);
579 if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) {
580 req->status = NT_STATUS_BUFFER_TOO_SMALL;
583 if (p->out.count == p->in.repeat_count) {
584 return smbcli_request_destroy(req);
587 return NT_STATUS_OK;
589 failed:
590 return smbcli_request_destroy(req);
593 /****************************************************************************
594 Send a echo (sync interface)
595 *****************************************************************************/
596 NTSTATUS smb_raw_echo(struct smbcli_transport *transport, struct smb_echo *p)
598 struct smbcli_request *req = smb_raw_echo_send(transport, p);
599 return smbcli_request_simple_recv(req);