a9ff8f33c57225452f412bf7baf2023a18c1ce17
[samba.git] / source4 / libcli / raw / clitransport.c
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 {
40         smbcli_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT);
41         return 0;
42 }
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 {
52         struct smbcli_transport *transport;
53         uint32_t smb1_capabilities;
54
55         transport = talloc_zero(parent_ctx, struct smbcli_transport);
56         if (!transport) return NULL;
57
58         transport->ev = sock->event.ctx;
59         transport->options = *options;
60
61         TALLOC_FREE(sock->event.fde);
62         TALLOC_FREE(sock->event.te);
63
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;
71
72         if (options->ntstatus_support) {
73                 smb1_capabilities |= CAP_STATUS32;
74         }
75
76         if (options->unicode) {
77                 smb1_capabilities |= CAP_UNICODE;
78         }
79
80         if (options->use_spnego) {
81                 smb1_capabilities |= CAP_EXTENDED_SECURITY;
82         }
83
84         if (options->use_level2_oplocks) {
85                 smb1_capabilities |= CAP_LEVEL_II_OPLOCKS;
86         }
87
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         if (transport->conn == NULL) {
95                 TALLOC_FREE(sock);
96                 TALLOC_FREE(transport);
97                 return NULL;
98         }
99         sock->sock->fd = -1;
100         TALLOC_FREE(sock);
101
102         talloc_set_destructor(transport, transport_destructor);
103
104         return transport;
105 }
106
107 /*
108   mark the transport as dead
109 */
110 void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status)
111 {
112         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
113                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
114         }
115         if (NT_STATUS_IS_OK(status)) {
116                 status = NT_STATUS_LOCAL_DISCONNECT;
117         }
118
119         smbXcli_conn_disconnect(transport->conn, status);
120 }
121
122 static void idle_handler(struct tevent_context *ev, 
123                          struct tevent_timer *te, struct timeval t, void *private_data)
124 {
125         struct smbcli_transport *transport = talloc_get_type(private_data,
126                                                              struct smbcli_transport);
127         struct timeval next;
128
129         transport->idle.func(transport, transport->idle.private_data);
130
131         next = timeval_current_ofs_usec(transport->idle.period);
132
133         transport->idle.te = tevent_add_timer(transport->ev,
134                                               transport,
135                                               next,
136                                               idle_handler,
137                                               transport);
138 }
139
140 /*
141   setup the idle handler for a transport
142   the period is in microseconds
143 */
144 _PUBLIC_ void smbcli_transport_idle_handler(struct smbcli_transport *transport, 
145                                    void (*idle_func)(struct smbcli_transport *, void *),
146                                    uint64_t period,
147                                    void *private_data)
148 {
149         TALLOC_FREE(transport->idle.te);
150
151         transport->idle.func = idle_func;
152         transport->idle.private_data = private_data;
153         transport->idle.period = period;
154
155         transport->idle.te = tevent_add_timer(transport->ev,
156                                               transport,
157                                               timeval_current_ofs_usec(period),
158                                               idle_handler,
159                                               transport);
160 }
161
162 /*
163   process some read/write requests that are pending
164   return false if the socket is dead
165 */
166 _PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport)
167 {
168         struct tevent_req *subreq = NULL;
169         int ret;
170
171         if (!smbXcli_conn_is_connected(transport->conn)) {
172                 return false;
173         }
174
175         if (!smbXcli_conn_has_async_calls(transport->conn)) {
176                 return true;
177         }
178
179         /*
180          * do not block for more than 500 micro seconds
181          */
182         subreq = tevent_wakeup_send(transport,
183                                     transport->ev,
184                                     timeval_current_ofs_usec(500));
185         if (subreq == NULL) {
186                 return false;
187         }
188
189         ret = tevent_loop_once(transport->ev);
190         if (ret != 0) {
191                 return false;
192         }
193
194         TALLOC_FREE(subreq);
195
196         if (!smbXcli_conn_is_connected(transport->conn)) {
197                 return false;
198         }
199
200         return true;
201 }
202
203 static void smbcli_transport_break_handler(struct tevent_req *subreq);
204 static void smbcli_request_done(struct tevent_req *subreq);
205
206 struct tevent_req *smbcli_transport_setup_subreq(struct smbcli_request *req)
207 {
208         struct smbcli_transport *transport = req->transport;
209         uint8_t smb_command;
210         uint8_t additional_flags;
211         uint8_t clear_flags;
212         uint16_t additional_flags2;
213         uint16_t clear_flags2;
214         uint32_t pid;
215         uint16_t tid;
216         uint16_t uid;
217         uint32_t timeout_msec = transport->options.request_timeout * 1000;
218         struct iovec *bytes_iov = NULL;
219         struct tevent_req *subreq = NULL;
220
221         smb_command = SVAL(req->out.hdr, HDR_COM);
222         additional_flags = CVAL(req->out.hdr, HDR_FLG);
223         additional_flags2 = SVAL(req->out.hdr, HDR_FLG2);
224         pid  = SVAL(req->out.hdr, HDR_PID);
225         pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16;
226         tid = SVAL(req->out.hdr, HDR_TID);
227         uid = SVAL(req->out.hdr, HDR_UID);
228
229         clear_flags = ~additional_flags;
230         clear_flags2 = ~additional_flags2;
231
232         bytes_iov = talloc(req, struct iovec);
233         if (bytes_iov == NULL) {
234                 return NULL;
235         }
236         bytes_iov->iov_base = (void *)req->out.data;
237         bytes_iov->iov_len = req->out.data_size;
238
239         subreq = smb1cli_req_create(req,
240                                     transport->ev,
241                                     transport->conn,
242                                     smb_command,
243                                     additional_flags,
244                                     clear_flags,
245                                     additional_flags2,
246                                     clear_flags2,
247                                     timeout_msec,
248                                     pid,
249                                     tid,
250                                     uid,
251                                     req->out.wct,
252                                     (uint16_t *)req->out.vwv,
253                                     1, bytes_iov);
254         if (subreq == NULL) {
255                 return NULL;
256         }
257
258         ZERO_STRUCT(req->out);
259
260         return subreq;
261 }
262
263 /*
264   put a request into the send queue
265 */
266 void smbcli_transport_send(struct smbcli_request *req)
267 {
268         struct smbcli_transport *transport = req->transport;
269         NTSTATUS status;
270         bool need_pending_break = false;
271         struct tevent_req *subreq = NULL;
272         size_t i;
273         size_t num_subreqs = 0;
274
275         if (transport->oplock.handler) {
276                 need_pending_break = true;
277         }
278
279         if (transport->break_subreq) {
280                 need_pending_break = false;
281         }
282
283         if (need_pending_break) {
284                 subreq = smb1cli_req_create(transport,
285                                             transport->ev,
286                                             transport->conn,
287                                             0, /* smb_command */
288                                             0, /* additional_flags */
289                                             0, /* clear_flags */
290                                             0, /* additional_flags2 */
291                                             0, /* clear_flags2 */
292                                             0, /* timeout_msec */
293                                             0, /* pid */
294                                             0, /* tid */
295                                             0, /* uid */
296                                             0, /* wct */
297                                             NULL, /* vwv */
298                                             0, /* iov_count */
299                                             NULL); /* bytes_iov */
300                 if (subreq != NULL) {
301                         smb1cli_req_set_mid(subreq, 0xFFFF);
302                         smbXcli_req_set_pending(subreq);
303                         tevent_req_set_callback(subreq,
304                                                 smbcli_transport_break_handler,
305                                                 transport);
306                         transport->break_subreq = subreq;
307                         subreq = NULL;
308                 }
309         }
310
311         subreq = smbcli_transport_setup_subreq(req);
312         if (subreq == NULL) {
313                 req->state = SMBCLI_REQUEST_ERROR;
314                 req->status = NT_STATUS_NO_MEMORY;
315                 return;
316         }
317
318         for (i = 0; i < ARRAY_SIZE(req->subreqs); i++) {
319                 if (req->subreqs[i] == NULL) {
320                         req->subreqs[i] = subreq;
321                         subreq = NULL;
322                 }
323                 if (req->subreqs[i] == NULL) {
324                         break;
325                 }
326
327                 if (!tevent_req_is_in_progress(req->subreqs[i])) {
328                         req->state = SMBCLI_REQUEST_ERROR;
329                         req->status = NT_STATUS_INTERNAL_ERROR;
330                         return;
331                 }
332         }
333         num_subreqs = i;
334
335         req->state = SMBCLI_REQUEST_RECV;
336         tevent_req_set_callback(req->subreqs[0], smbcli_request_done, req);
337
338         status = smb1cli_req_chain_submit(req->subreqs, num_subreqs);
339         if (!NT_STATUS_IS_OK(status)) {
340                 req->status = status;
341                 req->state = SMBCLI_REQUEST_ERROR;
342                 smbXcli_conn_disconnect(transport->conn, status);
343         }
344 }
345
346 static void smbcli_request_done(struct tevent_req *subreq)
347 {
348         struct smbcli_request *req =
349                 tevent_req_callback_data(subreq,
350                 struct smbcli_request);
351         struct smbcli_transport *transport = req->transport;
352         ssize_t len;
353         size_t i;
354         uint8_t *hdr = NULL;
355         uint8_t wct = 0;
356         uint16_t *vwv = NULL;
357         uint32_t num_bytes = 0;
358         uint8_t *bytes = NULL;
359         struct iovec *recv_iov = NULL;
360         uint8_t *inbuf = NULL;
361
362         req->status = smb1cli_req_recv(req->subreqs[0], req,
363                                        &recv_iov,
364                                        &hdr,
365                                        &wct,
366                                        &vwv,
367                                        NULL, /* pvwv_offset */
368                                        &num_bytes,
369                                        &bytes,
370                                        NULL, /* pbytes_offset */
371                                        &inbuf,
372                                        NULL, 0); /* expected */
373         TALLOC_FREE(req->subreqs[0]);
374         if (!NT_STATUS_IS_OK(req->status)) {
375                 if (recv_iov == NULL) {
376                         req->state = SMBCLI_REQUEST_ERROR;
377                         transport->error.e.nt_status = req->status;
378                         transport->error.etype = ETYPE_SOCKET;
379                         if (req->async.fn) {
380                                 req->async.fn(req);
381                         }
382                         return;
383                 }
384         }
385
386         /*
387          * For SMBreadBraw hdr is NULL
388          */
389         len = recv_iov[0].iov_len;
390         for (i=1; hdr != NULL && i < 3; i++) {
391                 uint8_t *p = recv_iov[i-1].iov_base;
392                 uint8_t *c1 = recv_iov[i].iov_base;
393                 uint8_t *c2 = p + recv_iov[i-1].iov_len;
394
395                 len += recv_iov[i].iov_len;
396
397                 c2 += i;
398                 len += i;
399
400                 if (recv_iov[i].iov_len == 0) {
401                         continue;
402                 }
403
404                 if (c1 != c2) {
405                         req->state = SMBCLI_REQUEST_ERROR;
406                         req->status = NT_STATUS_INTERNAL_ERROR;
407                         transport->error.e.nt_status = req->status;
408                         transport->error.etype = ETYPE_SMB;
409                         if (req->async.fn) {
410                                 req->async.fn(req);
411                         }
412                         return;
413                 }
414         }
415
416         /* fill in the 'in' portion of the matching request */
417         req->in.buffer = inbuf;
418         req->in.size = NBT_HDR_SIZE + len;
419         req->in.allocated = req->in.size;
420
421         req->in.hdr = hdr;
422         req->in.vwv = (uint8_t *)vwv;
423         req->in.wct = wct;
424         req->in.data = bytes;
425         req->in.data_size = num_bytes;
426         req->in.ptr = req->in.data;
427         if (hdr != NULL) {
428                 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
429         }
430
431         smb_setup_bufinfo(req);
432
433         transport->error.e.nt_status = req->status;
434         if (NT_STATUS_IS_OK(req->status)) {
435                 transport->error.etype = ETYPE_NONE;
436         } else {
437                 transport->error.etype = ETYPE_SMB;
438         }
439
440         req->state = SMBCLI_REQUEST_DONE;
441         if (req->async.fn) {
442                 req->async.fn(req);
443         }
444 }
445
446 static void smbcli_transport_break_handler(struct tevent_req *subreq)
447 {
448         struct smbcli_transport *transport =
449                 tevent_req_callback_data(subreq,
450                 struct smbcli_transport);
451         NTSTATUS status;
452         struct iovec *recv_iov = NULL;
453         uint8_t *hdr = NULL;
454         uint16_t *vwv = NULL;
455         const struct smb1cli_req_expected_response expected[] = {
456         {
457                 .status = NT_STATUS_OK,
458                 .wct = 8,
459         }
460         };
461         uint16_t tid;
462         uint16_t fnum;
463         uint8_t level;
464
465         transport->break_subreq = NULL;
466
467         status = smb1cli_req_recv(subreq, transport,
468                                   &recv_iov,
469                                   &hdr,
470                                   NULL, /* pwct */
471                                   &vwv,
472                                   NULL, /* pvwv_offset */
473                                   NULL, /* pnum_bytes */
474                                   NULL, /* pbytes */
475                                   NULL, /* pbytes_offset */
476                                   NULL, /* pinbuf */
477                                   expected,
478                                   ARRAY_SIZE(expected));
479         TALLOC_FREE(subreq);
480         if (!NT_STATUS_IS_OK(status)) {
481                 TALLOC_FREE(recv_iov);
482                 smbcli_transport_dead(transport, status);
483                 return;
484         }
485
486         /*
487          * Setup the subreq to handle the
488          * next incoming SMB2 Break.
489          */
490         subreq = smb1cli_req_create(transport,
491                                     transport->ev,
492                                     transport->conn,
493                                     0, /* smb_command */
494                                     0, /* additional_flags */
495                                     0, /* clear_flags */
496                                     0, /* additional_flags2 */
497                                     0, /* clear_flags2 */
498                                     0, /* timeout_msec */
499                                     0, /* pid */
500                                     0, /* tid */
501                                     0, /* uid */
502                                     0, /* wct */
503                                     NULL, /* vwv */
504                                     0, /* iov_count */
505                                     NULL); /* bytes_iov */
506         if (subreq != NULL) {
507                 smb1cli_req_set_mid(subreq, 0xFFFF);
508                 smbXcli_req_set_pending(subreq);
509                 tevent_req_set_callback(subreq,
510                                         smbcli_transport_break_handler,
511                                         transport);
512                 transport->break_subreq = subreq;
513         }
514
515         tid = SVAL(hdr, HDR_TID);
516         fnum = SVAL(vwv+2, 0);
517         level = CVAL(vwv+3, 1);
518
519         TALLOC_FREE(recv_iov);
520
521         if (transport->oplock.handler) {
522                 transport->oplock.handler(transport, tid, fnum, level,
523                                           transport->oplock.private_data);
524         } else {
525                 DEBUG(5,("Got SMB oplock break with no handler\n"));
526         }
527
528 }
529
530
531 /****************************************************************************
532  Send an SMBecho (async send)
533 *****************************************************************************/
534 _PUBLIC_ struct smbcli_request *smb_raw_echo_send(struct smbcli_transport *transport,
535                                          struct smb_echo *p)
536 {
537         struct smbcli_request *req;
538
539         req = smbcli_request_setup_transport(transport, SMBecho, 1, p->in.size);
540         if (!req) return NULL;
541
542         SSVAL(req->out.vwv, VWV(0), p->in.repeat_count);
543
544         memcpy(req->out.data, p->in.data, p->in.size);
545
546         ZERO_STRUCT(p->out);
547
548         if (!smbcli_request_send(req)) {
549                 smbcli_request_destroy(req);
550                 return NULL;
551         }
552
553         return req;
554 }
555
556 /****************************************************************************
557  raw echo interface (async recv)
558 ****************************************************************************/
559 NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
560                            struct smb_echo *p)
561 {
562         if (!smbcli_request_receive(req) ||
563             smbcli_request_is_error(req)) {
564                 goto failed;
565         }
566
567         SMBCLI_CHECK_WCT(req, 1);
568         p->out.count++;
569         p->out.sequence_number = SVAL(req->in.vwv, VWV(0));
570         p->out.size = req->in.data_size;
571         talloc_free(p->out.data);
572         p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size);
573         NT_STATUS_HAVE_NO_MEMORY(p->out.data);
574
575         if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) {
576                 req->status = NT_STATUS_BUFFER_TOO_SMALL;
577         }
578
579         if (p->out.count == p->in.repeat_count) {
580                 return smbcli_request_destroy(req);
581         }
582
583         return NT_STATUS_OK;
584
585 failed:
586         return smbcli_request_destroy(req);
587 }
588
589 /****************************************************************************
590  Send a echo (sync interface)
591 *****************************************************************************/
592 NTSTATUS smb_raw_echo(struct smbcli_transport *transport, struct smb_echo *p)
593 {
594         struct smbcli_request *req = smb_raw_echo_send(transport, p);
595         return smbcli_request_simple_recv(req);
596 }